Windows 拖放操作直觀高效,C++ Builder 5 (CB5) 提供豐富的 VCL 屬性與事件支援拖放功能。本文分兩大場景詳細說明:工具列停靠拖放 與 任意控件間資料拖放,附完整屬性設定與事件程式碼。
利用 CoolBar + ToolBar + 三個關鍵屬性即可實現:
| 屬性 | 說明 | 設定值 |
|---|---|---|
DockSite | 指定控件是否接受停靠操作 | CoolBar1->DockSite = true; |
DragKind | 拖放類型:dkDrag(自由拖曳) / dkDock(停靠) | ToolBar1->DragKind = dkDock; |
DragMode | 拖放模式:dmAutomatic(自動) / dmManual(手動呼叫 BeginDrag) | ToolBar1->DragMode = dmAutomatic; |
所有 ToolBar 設定相同屬性後,編譯執行即可像 Office 工具列一樣自由拖曳停靠。
BeginDrag:手動模式下啟動拖放。OnDragOver:拖曳物件經過目標控件時觸發,Accept 參數決定是否接受。OnDragDrop:在目標控件釋放滑鼠時觸發,執行實際資料移動/複製邏輯。OnStartDrag:開始拖放時觸發,可記錄來源索引等狀態。
// 兩個 ListBox 皆設為多選、自動拖放模式
ListBox1->MultiSelect = true;
ListBox1->DragMode = dmAutomatic;
ListBox2->MultiSelect = true;
ListBox2->DragMode = dmAutomatic;
// 共用事件處理函數
ListBox2->OnDragOver = ListBox1DragOver;
ListBox2->OnDragDrop = ListBox1DragDrop;
ListBox2->OnStartDrag = ListBox1StartDrag;
標頭檔宣告兩個整數變數:int CurIndex, NewIndex;
// 開始拖放:記錄來源項目索引
void __fastcall TForm1::ListBox1StartDrag(TObject *Sender, TDragObject *&DragObject) {
CurIndex = ((TListBox*)Sender)->ItemIndex;
}
// 拖放經過:僅接受來源也是 TListBox 的情況
void __fastcall TForm1::ListBox1DragOver(TObject *Sender, TObject *Source, int X, int Y, TDragState State, bool &Accept) {
Accept = Source->ClassNameIs("TListBox") && Sender->ClassNameIs("TListBox");
}
// 拖放釋放:核心邏輯
void __fastcall TForm1::ListBox1DragDrop(TObject *Sender, TObject *Source, int X, int Y) {
if (Sender == Source) {
// 同一控件內:交換項目順序
NewIndex = Y / ListBox1->ItemHeight;
if (NewIndex >= ((TListBox*)Sender)->Items->Count)
NewIndex = ((TListBox*)Sender)->Items->Count - 1;
((TListBox*)Sender)->Items->Move(CurIndex, NewIndex);
} else {
// 不同控件間:移動/複製項目
TListBox *src = (TListBox*)Source;
TListBox *dst = (TListBox*)Sender;
if (src->SelCount == 1) {
// 單選:移動單一項目
dst->Items->Add(src->Items->Strings[src->ItemIndex]);
src->Items->Delete(src->ItemIndex);
}
if (src->SelCount >= 1) {
// 多選:批次移動(從後往前刪除避免索引錯亂)
for (int i = 0; i < src->Items->Count; i++)
if (src->Selected[i])
dst->Items->Add(src->Items->Strings[i]);
for (int i = src->Items->Count - 1; i >= 0; i--)
if (src->Selected[i])
src->Items->Delete(i);
}
}
}
| 場景 | 核心機制 | 適用控件 |
|---|---|---|
| 工具列停靠 | DockSite + DragKind=dkDock + DragMode=dmAutomatic | CoolBar, ToolBar, Panel 等支援停靠的容器 |
| 控件間資料拖放 | OnDragOver 判斷接受 + OnDragDrop 執行資料轉移 | 所有 TControl 衍生控件(ListBox, TreeView, ListView, Edit 等) |
IDropTarget/IDataObject COM 介面,支援檔案、文字、自訂格式。OnDragOver 中根據 Accept 變更游標 (Screen->Cursors) 或繪製插入標記。OnEndDrag 事件處理使用者按 Esc 取消或拖放到無效區域的清理邏輯。TDragObject 或 TDragObjectEx 攜帶複雜資料結構。C++ Builder 的 VCL 封裝讓基礎拖放功能極易實現,掌握核心事件流程即可構建直觀的使用者介面互動。