| 角色 | 基類 | 關鍵屬性 | 值 |
|---|---|---|---|
| 被停靠端 (容器) | TWinControl | DockSite | True |
| 停靠端 (客戶端) | TControl | DragKind | dkDock |
| DragMode | dmAutomatic (自動拖曳) |
TPanel (如 LeftDockPanel):Align=alLeft、Width=0、DockSite=TrueTSplitter (如 LeftSplitter):Align=alLeft,可調整面板寬度DragKind=dkDock、DragMode=dmAutomatic| 事件 | 觸發時機 | 關鍵參數 | 主要用途 |
|---|---|---|---|
OnDockOver | 客戶端掠過容器 | Source: TDragDockObject; X,Y; State; var Accept | 控制**預覽矩形**位置、決定是否接受 |
OnDockDrop | 客戶端釋放於容器 | Source; X,Y | 設定容器最終尺寸、完成停靠佈局 |
OnGetSiteInfo | 客戶端移動中 (高頻) | DockClient; var InfluenceRect; MousePos; var CanDock | 查詢是否可停靠、影響區域 |
OnStartDock | 客戶端開始拖曳 | var DragObject | 自訂拖曳物件、初始化 |
OnEndDock | 客戶端結束拖曳 (無論成功) | Target; X,Y | 清理、狀態重置 |
OnUnDock | 客戶端從容器拖出 (浮動) | Client; NewTarget; var Allow | 控制是否允許浮動、恢復容器狀態 |
procedure TMainForm.LeftDockPanelDockOver(Sender: TObject; Source: TDragDockObject; X, Y: Integer; State: TDragState; var Accept: Boolean);
var ARect: TRect;
begin
Accept := Source.Control is TDockableForm;
if Accept then begin
ARect.TopLeft := LeftDockPanel.ClientToScreen(Point(0,0));
ARect.BottomRight := LeftDockPanel.ClientToScreen(Point(ClientWidth div 3, LeftDockPanel.Height));
Source.DockRect := ARect; // 虛線預覽區域
end;
end;
procedure TMainForm.LeftDockPanelDockDrop(Sender: TObject; Source: TDragDockObject; X, Y: Integer);
begin
LeftDockPanel.Width := ClientWidth div 3;
LeftSplitter.Left := LeftDockPanel.Width + LeftSplitter.Width;
end;
procedure TDockableForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
MainForm.LeftDockPanel.Width := 0; // 隱藏面板
Action := caHide; // 隱藏而非釋放
end;
private
procedure CMDockClient(var Msg: TCMDockClient); message CM_DOCKCLIENT;
procedure TDockableForm.CMDockClient(var Msg: TCMDockClient);
var Host: TForm;
begin
if Msg.DockSource.Control is TDockableForm then begin
Host := TTiledHost.Create(Application); // 宿主視窗
Host.BoundsRect := Self.BoundsRect;
Self.ManualDock(Host, nil, alNone);
Self.DockSite := False; // 變為客戶端
Msg.DockSource.Control.ManualDock(Host, nil, alNone);
TDockableForm(Msg.DockSource.Control).DockSite := False;
Host.Visible := True;
end;
end;
ManualDock(NewDockSite, DropControl, ControlSide):安全程式化停靠TTiledHost 需 DockSite=True
procedure TDockableForm.CMDockClient(var Msg: TCMDockClient);
var Host: TTabHost; // 含 PageControl1 (Align=alClient, DockSite=True)
begin
if Msg.DockSource.Control is TDockableForm then begin
Host := TTabHost.Create(Application);
Host.BoundsRect := Self.BoundsRect;
Self.ManualDock(Host.PageControl1, nil, alClient);
Msg.DockSource.Control.ManualDock(Host.PageControl1, nil, alClient);
Host.Visible := True;
end;
end;
TPageControl 內建處理 CM_DOCKCLIENT/CM_DOCKNOTIFICATION/CM_UNDOCKCLIENT,自動建立分頁。
TControlBar/TCoolBar:DockSite=TrueTToolBar:DragKind=dkDock、DragMode=dmAutomaticFloatingDockSiteClass:指定浮動時的宿主視窗類別 (設計時設定,運行時自動建立)| 分類 | 成員 | 說明 |
|---|---|---|
| 尺寸記憶 | TBDockHeight | 停靠時高度 |
| LRDockWidth | 停靠時寬度 | |
| UnDockHeight | 浮動時高度 | |
| UnDockWidth | 浮動時寬度 | |
| 關係查詢 | HostDockSite | 所在容器實例 |
| FloatingDockSiteClass | 浮動宿主類別 | |
| Floating | 是否浮動狀態 | |
| 容器管理 | DockClientCount | 已停靠客戶端數 |
| DockClients[Index] | 客戶端列表 | |
| DockManager / UseDockManager | 停靠管理器 (TDockTree ActiveX) | |
| 方法 | ManualFloat | 程式化浮動 |
| ReplaceDockedControl | 替換已停靠控件 | |
| DoAddDockClient / DockDrop / DockOver / DoDockOver / DoUnDock | 內部虛擬方法,可覆寫擴充 |
CM_DOCKCLIENT:停靠請求 (含 TCMDockClient 結構)CM_DOCKNOTIFICATION:停靠完成通知CM_UNDOCKCLIENT:取消停靠通知Delphi\Demos\Docking\ 目錄包含完整示範專案。
Delphi 停靠架構極度成熟:DockSite + DragKind = 基礎;六大事件 = 精細控制;CM_DOCKCLIENT + ManualDock = 表單間自由組合;TPageControl = 內建頁簽宿主;ToolBar/CoolBar = 工具列停靠標準。掌握此體系,可輕鬆構建媲美 IDE 的專業級可停靠介面。