項目需在MFC對話框中顯示上萬條記錄(甚至10萬+),普通CListCtrl逐行插入數據極其緩慢,界面卡頓嚴重。經調研發現虛擬列表模式可完美解決此問題。
LVN_GETDISPINFO通知獲取資源編輯器中 List Control 屬性 → Styles → 勾選 Owner Data (LVS_OWNERDATA)
// 數據結構
struct Record {
CString id;
CString name;
CString department;
// ... 其他字段
};
std::vector g_records; // 全局/成員變量存儲所有數據
// 初始化時設置虛擬項目數 m_listCtrl.SetItemCountEx(g_records.size(), LVSICF_NOSCROLL | LVSICF_NOINVALIDATEALL);
void CMyDlg::OnLvnGetdispinfoList(NMHDR* pNMHDR, LRESULT* pResult) {
NMLVDISPINFO* pDispInfo = reinterpret_cast(pNMHDR);
if (pDispInfo->item.mask & LVIF_TEXT) {
int row = pDispInfo->item.iItem;
int col = pDispInfo->item.iSubItem;
if (row >= 0 && row < (int)g_records.size()) {
CString text;
switch (col) {
case 0: text = g_records[row].id; break;
case 1: text = g_records[row].name; break;
case 2: text = g_records[row].department; break;
// ... 其他列
}
// 關鍵:複製文本到緩衝區
lstrcpyn(pDispInfo->item.pszText, text, pDispInfo->item.cchTextMax);
}
}
*pResult = 0;
}
BEGIN_MESSAGE_MAP(CMyDlg, CDialogEx)
ON_NOTIFY(LVN_GETDISPINFO, IDC_LIST_CTRL, &CMyDlg::OnLvnGetdispinfoList)
END_MESSAGE_MAP()
對頻繁訪問的行/列實現 LRU 緩存,減少數據源查詢開銷。
// 後台線程加載數據,完成後 PostMessage 通知 UI 線程 // UI 線程收到消息後調用 SetItemCountEx 刷新行數
結合 NM_CUSTOMDRAW 實現行顏色交替、高亮選中、圖標顯示等豐富視覺效果。
// 處理 HDN_ITEMCLICK 消息 // 根據點擊列對 g_records 進行 std::sort // 排序完成後 Invalidate() 觸發重繪
虛擬列表是MFC大數據顯示的銀彈。核心在於:數據與視圖分離、按需渲染、消息驅動獲取。正確實現 LVN_GETDISPINFO 處理器,配合 SetItemCountEx 設置行數,即可實現百萬級數據的毫秒級響應。建議所有涉及大量列表數據的MFC項目優先採用此模式。