普通的 CListCtrl 在其數據達到10000以上時,拖動滾動條已卡,很不好。。
Virtual List Controls,虛擬列表,我認爲是一種列表的顯示方式。。
普通列表:所有的列表數據加載完成再顯示。
虛擬列表:只加載當前指定的要顯示的數據(當收到 LVN_GETDISPINFO 消息時,會刷新列表,只刷新要顯示的部分 )。
很明顯,當數據量大的時候,誰優誰劣。。
比起 MFC,我更喜歡輕量級 WTL,就用 WTL 做個例子吧。。
1、新建 WTL 工程:
2、拖出列表控件 List Control:
我設其 ID 爲 IDC_LIST_LOVE,View 爲 Report,Owner Data 爲 True
3、用 WTL 的 CListViewCtrl 去關聯這個列表 IDC_LIST_LOVE,並插入列:
我設了個 CListViewCtrl 的成員變量 m_lvcLove
//set virtual list
m_lvcLove.Attach(GetDlgItem(IDC_LIST_LOVE));
m_lvcLove.AddColumn(_T("海誓山盟"), 0);
m_lvcLove.AddColumn(_T("往事如煙"), 1);
4、消息宏中關聯 LVN_GETDISPINFO 消息、列表 ID 和響應函數:
NOTIFY_HANDLER(IDC_LIST_LOVE, LVN_GETDISPINFO, OnGetDispInfo)
5、完成響應函數:
pItem 在這裏就是列表控件的單元格,要想列表的這個單元格顯示什麼,就對 pItem 進行什麼樣的操作,至於 pItem 是如何顯示在列表上的,並不用我們寫在代碼中
pItem->mask 是顯示內容的標誌,指定要顯示圖標、文字或是其他
pItem->iItem 是列表控件的行號(從0開始)
pItem->iSubItem 是列表控件的列號(從0開始)
LRESULT CMainDlg::OnGetDispInfo(int /*idCtrl*/, LPNMHDR pnmh, BOOL& /*bHandled*/)
{
NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pnmh);
LV_ITEM* pItem = &(pDispInfo)->item;
int nItem = pItem->iItem;
if (pItem->mask & LVIF_TEXT) //valid text buffer?
{
switch (pItem->iSubItem)
{
case 0: //fill in main text
lstrcpy(pItem->pszText, m_vtLove[nItem].strSaying);
break;
case 1: //fill in sub item 1 text
lstrcpy(pItem->pszText, m_vtLove[nItem].strHistory);
break;
}
}
return 0;
}
6、主動觸發列表更新(SetItemCount 非常關鍵,這會觸發 LVN_GETDISPINFO 消息):
我用了一個Add Data 的按鈕,每按一次加入1000條數據
LRESULT CMainDlg::OnAddData(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
int nBase = m_vtLove.size();
for (int i = 0; i < ADD_COUNT_ONE_TIME; ++i)
{
CString strHistory;
strHistory.Format(_T("%d days"), nBase + i);
m_vtLove.push_back(LOVEITEM(_T("I love you"), strHistory));
}
m_lvcLove.SetItemCount(m_vtLove.size());
return 0;
}
7、看看效果吧:
我點了10次,加了10000條數據,隨便拉滾動條,一點都不卡。。