程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> Delphi中停靠技術的實現(2)

Delphi中停靠技術的實現(2)

編輯:Delphi

 


OnStartDock和OnEndDock經常會被觸發,

OnUnDock只在停靠窗體變成浮動時觸發

講了那麼多,大家有沒有被搞糊塗?那好,我來做一下總結:

在Delphi中只要是從TWinControl繼承的控件都支持被停靠(如上面的LeftDockPanel),也就是有DockSite這個屬性;所有從TControl繼承的控件都支持停靠(如上面的DockableForm),也就是有DragKind這個屬性.所以支持被停靠的控件都支持停靠,支持停靠的控件不一定支持被停靠,道理很簡單,因為TWinControl繼承於TControl。OnDockOver事件是控制停靠窗體的預覽位置;OnDockDrap事件是控制停靠窗體的最終位置;OnGetSiteInfo是詢問是否可以停靠;OnStartDock是停靠開始,OnEndDock是停靠結尾,OnUnDock是不停靠(也就是被拖出來時)。



想必Delphi用的熟的大蝦都知道在Delphi的可停靠窗體間可以相互停靠,而且花樣還很多,可以停靠成並排的,也可以停靠成PageControl樣式的,兩個可停靠窗體合並後的窗體又可以再和別的可停靠窗體合並,形成樹狀。下面來介紹這方面的技術:

說道這裡,我們不得不介紹一下CM_DOCKCLIENT消息和TCMDockClient結構,

CM_DOCKCLIENT消息和TCMDockClient結構是相互對應的,TCMDockClient的結構是:

 TCMDockClient = packed record

   Msg: Cardinal;

   DockSource: TDragDockObject;

   MousePos: TSmallPoint;

   Result: Integer;

 end;

其中DockSource包含了停靠—拖動操作的信息,前面已經提到過;MousePos是鼠標的位置。CM_DOCKCLIENT事件在停靠和被停靠控件都可以捕獲,因為它是TWinControl類發出的,

代碼如下:

procedure TWinControl.DockDrop(Source: TDragDockObject; X, Y: Integer);

begin

 if (Perform(CM_DOCKCLIENT, Integer(Source), Integer(SmallPoint(X, Y))) >= 0)

   and Assigned(FOnDockDrop) then

   FOnDockDrop(Self, Source, X, Y);

end;



可以看出,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有深刻研究的大蝦都知道怎麼做了。





下面我來講一下兩個窗體怎樣停靠成PageControl樣式。

首先創建一個窗體,叫TabHost,在它上面放一個PageControl,Align屬性設成alClient,讓它占滿整個TabHost,別忘了把PageControl的DockSite屬性設成True.

然後我們依次加入代碼:

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(ClientRect.TopLeft);

   ARect.BottomRight := ClientToScreen(ClientRect.BottomRight);

   Source.DockRect := ARect;

 end;



procedure TDockableForm.CMDockClient(var Message: TCMDockClient);

var

 Host: TForm;

begin

 if Message.DockSource.Control is TDockableForm then

 begin

     Host := TTabHost.Create(Application);

     Host.BoundsRect := Self.BoundsRect;

     Self.ManualDock(TTabHost(Host).PageControl1, nil, alClient);

 Message.DockSource.Control.ManualDock(TTabHost(Host).PageControl1, nil, alClient);

     Host.Visible := True;

      End;

End;

代碼的具體意思在這裡就不再解釋了,同理也可以讓TabHost具有停靠和被停靠的功能。還需要說明一下,TPageControl封裝了一些對停靠的支持,它捕獲了CM_DOCKCLIENT,

CM_DOCKNOTIFICATION,CM_UNDOCKCLIENT,WM_LBUTTONDBLCLK消息處理停靠動作。具體可以查看TPageControl的原代碼。



工具條的停靠也一樣,在主窗體上放一個ControlBar或CoolBar,把他們的DockSite設成True;再在上面放ToolBar, ToolBar的DragKind屬性設成dkDock,DragMode屬性設為dmAutomatic。在這裡,TControl有一個屬性叫FloatingDockSiteClass,它的類型是TWinControl的引用(class of TWinControl),只要在主窗口創建時,把ToolBar的FloatingDockSiteClass屬性設成某一個窗體A,比如在設計時A這個窗體叫ToolBarDockForm,但在程序裡面不用顯式的創建A,Delphi會自動創建,當ToolBar被拖動出來時,Delphi自動把它裝載到ToolBarDockForm裡,當然ToolBarDockForm也要象上面提到的DockableForm一樣設置一定的屬性和添加一些代碼。



講了一大堆,還是沒有把Delphi支持的停靠功能全部講完,據我所知,還有很多。還是把它們列出來供大家參考(前面介紹的就省略了)

屬性:

1.TControl. TBDockHeight               //存儲停靠控件在停靠時的的高度;

2.TControl. LRDockWidth                //存儲停靠控件在停靠時的的寬度;

3.TControl. UnDockHeight               //存儲停靠控件在浮動時的的高度;

4.TControl. UnDockWidth             &nbs

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved