MFC 內建 DBGrid 不僅介面醜陋、文件缺乏,且大量資料載入極慢。本文介紹如何利用 Chris Maunder 的 CGridCtrl 之虛模式,搭配記憶體對映檔,打造支援百萬筆記錄、秒級響應的資料庫表格控件 COdbcDBGridFile。
| 傳統 Grid | 虛模式 Grid |
|---|---|
| 需將所有資料寫入控件 | 僅按需請求可見儲存格資料 |
| 十萬筆資料載入需數秒 | 百萬筆資料瞬間顯示 |
| 記憶體佔用與筆數成正比 | 記憶體固定,僅存可見區域資料 |
SetVirtualMode(TRUE) 啟用虛模式SetRowCount(totalRows) 設定總列數(不實際配置)GVN_GETDISPINFO 通知GV_DISPINFO.item.row/col 即時回傳資料
class COdbcDBGridFile {
public:
COdbcDBGridFile(CGridCtrl* pGrid, CDatabase* pDB, CString strSQL, CString strMapFile);
int InitGrid(); // 初始化:建立對映檔、讀取欄位資訊
int SetGridText(GV_DISPINFO* pDispInfo); // 外部呼叫:填入儲存格文字
int Release(); // 釋放資源
private:
CGridCtrl* m_pGrid;
CDatabase* m_pDB;
CString m_strSQL;
// 記憶體對映檔相關成員...
// 快取機制:僅預讀可見範圍附近資料
};
SELECT COUNT(*) 設定 SetRowCountCreateFileMapping) 儲存資料列CGridCtrl 相關檔案與 OdbcDBGridFile.h/.cppMFCGridCtrl,ID 為 IDC_GRIDODBCCGridCtrl m_Grid,並在 DoDataExchange 加入 DDX_ControlCOdbcDBGridFile* m_pMapFile; CDatabase m_db;OnNotify 轉發 GVN_GETDISPINFO 給 m_pMapFile->SetGridText()Release() 釋放對映檔與資料庫連線
BOOL CDemo2Dlg::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) {
if (wParam == (WPARAM)m_Grid.GetDlgCtrlID()) {
*pResult = 1;
GV_DISPINFO* pDispInfo = (GV_DISPINFO*)lParam;
if (GVN_GETDISPINFO == pDispInfo->hdr.code) {
SetGridItem(pDispInfo);
return TRUE;
}
}
return CDialog::OnNotify(wParam, lParam, pResult);
}
void CDemo2Dlg::OnBtnQuery() {
Release(); // 釋放舊資源
UpdateData(TRUE);
CString strConn;
strConn.Format(_T("ODBC;DSN=%s;UID=%s;PWD=%s"), m_strSource, m_strUser, m_strPass);
if (!m_db.Open(strConn)) return;
m_pMapFile = new COdbcDBGridFile(&m_Grid, &m_db, m_strSql, _T("c:\\csl.txt"));
m_pMapFile->InitGrid();
}
若替換 MFC CDatabase/CRecordset 為作者前作 CMYODBC/CODBCSet,可再提升 3-5 倍查詢速度。配套原始碼提供 CMyODBCDBGridFile 實作。
COdbcDBGridFile 以 虛模式 + 記憶體對映檔 + 分批載入 三大技術,徹底解決 MFC 開發大量資料表格的效能痛點。介面僅 4 個公用函式,整合極簡單,是 VC++ 資料庫專案的利器。