TDBGrid 預設不處理滑鼠滾輪訊息,資料量大時僅能靠捲軸翻頁,體驗不佳。
WM_MOUSEWHEEL透過 SetWindowLong(GWL_WNDPROC) 替換視窗程序,在自訂 WindowProc 中處理滾輪訊息並轉發垂直捲動命令。
// 全域變數保存原始 WindowProc
FARPROC OldProc = NULL;
// 新視窗程序
LRESULT CALLBACK DBGridProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
if (uMsg == WM_MOUSEWHEEL) {
short zDelta = (short)HIWORD(wParam); // 滾輪增量 (+120/-120)
if (zDelta > 0)
::PostMessage(hWnd, WM_VSCROLL, SB_LINEUP, 0); // 向上一行
else
::PostMessage(hWnd, WM_VSCROLL, SB_LINEDOWN, 0); // 向下一行
return 0; // 已處理
}
// 其他訊息交給原始程序
return ::CallWindowProc(OldProc, hWnd, uMsg, wParam, lParam);
}
// 表單啟動時掛鉤
void __fastcall TMainForm::FormShow(TObject* Sender) {
// ... 資料庫連線程式碼 ...
OldProc = (FARPROC)::SetWindowLong(DBGrid->Handle, GWL_WNDPROC, (LONG)DBGridProc);
}
// 表單關閉時還原
void __fastcall TMainForm::FormClose(TObject* Sender, TCloseAction& Action) {
::SetWindowLong(DBGrid->Handle, GWL_WNDPROC, (LONG)OldProc);
// ... 關閉資料庫 ...
}
HIWORD(wParam) 取得滾輪增量(WHEEL_DELTA = 120)PostMessage 非同步發送 WM_VSCROLL,避免重入問題SB_LINEUP/SB_LINEDOWN 對應單行捲動CallWindowProc 確保原有訊息處理邏輯不受影響SetWindowLongPtr/GetWindowLongPtr 並改用 LONG_PTRzDelta,超過閾值改發送 SB_PAGEUP/SB_PAGEDOWNLOWORD(wParam) & MK_SHIFT 發送 WM_HSCROLLTDBGrid 衍生類別,建構子自動掛鉤,解構子自動還原| 方案 | 優點 | 缺點 |
|---|---|---|
| 子類化 (本文) | 無侵入、通用、效能佳 | 需注意 64 位元指標截斷 |
| Application->OnMessage | 純 VCL、無 API | 全域攔截、效能稍差 |
| 衍生 TDBGrid 覆寫 WndProc | 物件導向、封裝性好 | 需替換專案中所有 DBGrid |
| 第三方元件 | 功能豐富 | 增加依賴、體積大 |