實現類似瀏覽器中鍵/右鍵拖曳捲動體驗,需處理滑鼠捕獲、座標追蹤、捲動訊息發送三大核心邏輯。本文提供 TRichEdit 右鍵拖曳捲動完整實作程式碼。
bool RightButtonFlag; // 右鍵是否按下
bool RichEditDragFlag; // 是否進入拖曳捲動模式
int RightX, RightY; // 右鍵按下時座標
void __fastcall TMainForm::RichEditMouseDown(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y) {
if (Button == mbRight) {
RightButtonFlag = true;
Screen->Cursor = crHandPoint; // 手型游標提示
RightX = X;
RightY = Y;
SetCapture(RichEdit->Handle); // 獨佔滑鼠訊息
} else {
RightButtonFlag = false;
}
}
void __fastcall TMainForm::RichEditMouseMove(TObject *Sender,
TShiftState Shift, int X, int Y) {
if (RightButtonFlag) {
if (RightY > (Y + 8)) { // 向上移動超過閾值
RightY = Y;
SendMessage(RichEdit->Handle, EM_SCROLL, SB_LINEDOWN, 0); // 內容向下捲 (視覺向上)
} else if (RightY < (Y - 8)) { // 向下移動超過閾值
RightY = Y;
SendMessage(RichEdit->Handle, EM_SCROLL, SB_LINEUP, 0); // 內容向上捲 (視覺向下)
}
RichEditDragFlag = true; // 標記已進入拖曳模式
}
}
void __fastcall TMainForm::RichEditMouseUp(TObject *Sender,
TMouseButton Button, TShiftState Shift, int X, int Y) {
if (RightButtonFlag) ReleaseCapture();
if (RichEditDragFlag) {
// 已拖曳捲動:抑制右鍵選單,恢復預設游標
RightButtonFlag = false;
RichEditDragFlag = false;
Screen->Cursor = crDefault;
RichEdit->PopupMenu = NULL;
} else {
// 單純右鍵點擊:顯示右鍵選單
RichEdit->PopupMenu = RichEditPopupMenu;
}
}
| 機制 | API/屬性 | 作用 |
|---|---|---|
| 滑鼠捕獲 | SetCapture/ReleaseCapture | 確保滑鼠移出控制項仍收到 MouseMove |
| 捲動訊息 | EM_SCROLL + SB_LINEUP/SB_LINEDOWN | 逐行捲動,平滑自然 |
| 閾值判斷 | 8 像素 | 避免微小抖動觸發捲動,體驗更穩定 |
| 游標回饋 | crHandPoint/crDefault | 視覺提示可拖曳狀態 |
| 選單抑制 | PopupMenu = NULL/指派 | 拖曳結束不彈選單,單擊才彈 |
SB_LINEUP (0) // 向上捲動一行
SB_LINEDOWN (1) // 向下捲動一行
SB_PAGEUP (2) // 向上捲動一頁
SB_PAGEDOWN (3) // 向下捲動一頁
SB_THUMBPOSITION (4) // 定位至指定位置 (需配合 HIWORD)
SB_THUMBTRACK (5) // 拖曳捲動桿追蹤
SB_TOP (6) // 捲至頂端
SB_BOTTOM (7) // 捲至底端
TMemo、TListBox、TTreeView 等支援 EM_SCROLL 的控制項均可套用SB_PAGEUP/DOWN 實現加速捲動 (移動距離 > 某閾值)短短三個事件處理函數,即可賦予編輯控制項專業級的拖曳捲動體驗,展現了 Windows 訊息機制靈活組合的威力。