普通的 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条数据,随便拉滚动条,一点都不卡。。