容器 (接受停駐):
CoolBar1->DockSite = true; // 接受 dkDock 型別拖曳
可停駐控件 (工具列):
ToolBar1->DragKind = dkDock; // 停駐模式
ToolBar1->DragMode = dmAutomatic; // 自動啟動 (無需 OnDragOver 手寫)
其他 ToolBar 同理設定。編譯執行即可像 IDE 工具列一樣自由拖曳停駐。
| 事件 | 觸發時機 | 關鍵參數 | 用途 |
|---|---|---|---|
| OnDragOver | 拖曳物件進入/移動於控件上方 | Source, X, Y, State, Accept | 設定 Accept = true 允許放置,可根據 Source 類型決定 |
| OnDragDrop | 使用者在控件上釋放滑鼠 | Source, X, Y | 執行實際資料傳輸/動作 |
| OnEndDrag | 拖曳結束 (無論是否放置) | Target, X, Y | 來源控件清理/回饋 |
| OnStartDrag | dmManual 模式下開始拖曳 | DragObject | 自訂拖曳影像/資料物件 |
// 來源 ListBox1: DragMode = dmAutomatic
// 目標 ListBox2: DragMode = dmAutomatic
void __fastcall TForm1::ListBox2DragOver(TObject* Sender, TObject* Source, int X, int Y, TDragState State, bool& Accept) {
Accept = (Source == ListBox1); // 只接受來自 ListBox1
}
void __fastcall TForm1::ListBox2DragDrop(TObject* Sender, TObject* Source, int X, int Y) {
if (Source == ListBox1) {
int idx = ListBox1->ItemIndex;
if (idx >= 0) {
ListBox2->Items->Add(ListBox1->Items->Strings[idx]);
ListBox1->Items->Delete(idx); // 移動語義;複製則不刪除
}
}
}
void __fastcall TForm1::TreeView1StartDrag(TObject* Sender, TDragObject*& DragObject) {
// 建立自訂拖曳物件,可攜帶資料、自訂游標
DragObject = new TDragControlObjectEx(TreeView1);
// 或 TDragDockObjectEx 用於 Docking
}
DragMode = dmAutomatic。OnDragOver 檢查 Source 為 TDragFileObject (C++Builder 封裝) 或處理 WM_DROPFILES。DragAcceptFiles(Handle, TRUE) + 處理 WM_DROPFILES 取得檔案列表 (DragQueryFile)。| 問題 | 原因 | 解決 |
|---|---|---|
| 拖曳不啟動 | DragMode = dmManual 但未呼叫 BeginDrag | 設 dmAutomatic 或 OnMouseDown 呼叫 BeginDrag |
| 目標不接受 | OnDragOver 未設 Accept=true | 正確判斷 Source 類型並設 Accept |
| 拖曳游標錯誤 | 未處理 OnDragOver State 參數 | 根據 dsDragEnter/Leave/Move 更新游標 |
| Docking 後無法拖出 | 容器 DockSite=true 但子控件 DragKind≠dkDock | 子控件 DragKind=dkDock, DragMode=dmAutomatic |