標準 DBGrid、CListCtrl 逐行插入萬筆資料極慢、記憶體暴漲、滾動卡頓。CGridCtrl (CodeProject 經典開源專案) 提供虛擬模式:僅按需查詢可視區資料,支援百萬列流暢滾動。
m_Grid.SetVirtualMode(TRUE);
m_Grid.SetRowCount(nTotalRecords + 1); // +1 標題列
m_Grid.SetFixedRowCount(1);
m_Grid.SetColumnCount(nCols);
m_Grid.SetFixedColumnCount(1);
GVN_GETDISPINFO 通知處理BOOL CMyOdbcDlg::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
if (wParam == m_Grid.GetDlgCtrlID()) {
NMHDR* pHdr = (NMHDR*)lParam;
if (pHdr->code == GVN_GETDISPINFO) {
GV_DISPINFO* pDispInfo = (GV_DISPINFO*)lParam;
SetGridItem(pDispInfo); // 我們填充文字、圖示、格式
*pResult = 0;
return TRUE;
}
}
return CDialog::OnNotify(wParam, lParam, pResult);
}
void CMyOdbcDlg::SetGridItem(GV_DISPINFO* pInfo)
{
int row = pInfo->item.row; // 1-based (0=標題)
int col = pInfo->item.col; // 0-based
if (row == 0) { // 標題列
pInfo->item.strText = GetColumnCaption(col);
return;
}
// 從資料集取得第 row 筆資料第 col 欄位
// 策略 A:ADO Recordset 絕對定位 (較慢)
// 策略 B:快取當前頁 100 筆到 vector (推薦)
// 策略 C:異步預取下一頁,顯示 loading 佔位符
pInfo->item.strText = GetCachedCellText(row, col);
pInfo->item.lParam = row; // 可攜帶主鍵 ID
}
| 策略 | 適用場景 | 複雜度 |
|---|---|---|
| 全量快取 (vector) | < 5 萬列、欄位少 | 低 |
| 分頁快取 (LRU) | 百萬列、隨機跳轉 | 中 |
| 異步預取 + 佔位符 | 網路資料庫、高延遲 | 高 |
GVN_COLUMNCLICK,重新查詢 ORDER BY 並 Invalidate()。SetRowCount 更新總數。GVN_ENDLABELEDIT 取得新值 → 執行 UPDATE SQL → 更新快取。GetSelectedCellRange() 組裝 Tab 分隔文字 → OpenClipboard/SetClipboardData。