可以看出,TWinControl是先發送DOCKCLIENT消息,再觸發OnDockDrop事件的。
為了演示可停靠窗體之間相互停靠,我們先創建一個宿主窗體,取名叫TiledHost,把它的DockSite設成True。它的作用是用來裝載兩個DockableForm的。
首先在DockableForm中捕獲DOCKCLIENT消息,在裡面完成兩個窗體的相互停靠
聲明:
private
procedure CMDockClient(var Message: TCMDockClient); message CM_DOCKCLIENT;
end;
實現:
procedure TDockableForm.CMDockClient(var Message: TCMDockClIEnt);
var
Host: TForm;
begin
if Message.DockSource.Control is TDockableForm then
begin
Host := TTiledHost.Create(Application);
Host.BoundsRect := Self.BoundsRect;
Self.ManualDock(Host, nil, alNone);
Self.DockSite := False;
Message.DockSource.Control.ManualDock(Host, nil, alNone);
TDockableForm(Message.DockSource.Control).DockSite := False;
Host.Visible := True;
End;
end;
先解釋一下上面的代碼,首先創建TTiledHost的實例,然後用ManualDock函數把自己停靠到TTiledHost,把Message.DockSource.Control也停靠到TTiledHost,這樣就完成了窗體的相互停靠,當然,要是我們要程序產生停靠的預覽效果,就在DockableForm的OnDockOver事件裡加入代碼:
procedure TDockableForm.FormDockOver(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 := ClIEntToScreen(Point(0, 0));
ARect.BottomRight := ClIEntToScreen(
Point(ClientWidth div 2, ClIEntHeight));
Source.DockRect := ARect;
end;
end;
怎麼樣,效果還可以吧。對了,需要注意的是,用ManualDock函數可以安全的完成停靠功能,不要用Dock函數。ManualDock函數有一些參數:
function ManualDock(NewDockSite: TWinControl; DropControl: TControl = nil; ControlSide: TAlign = alNone): Boolean;
NewDockSite:要被停靠的窗體;
DropControl:已經存在於NewDockSite的TControl,在這裡可以把它設成nil;
ControlSide: 停靠的位置,可以是上,下,左,右,全部等。
當然,我們也可以讓TiledHost也具有和LeftDockPanel一樣有被停靠的功能,只要把TiledHost看成前面的LeftDockPanel,添加一些屬性和事件;把TiledHost看成DockableForm,
就可以有停靠的功能了。具體的做法這裡不再闡述了,相信對VCL有深刻研究的大蝦都知道怎麼做了。