a亚洲精品_精品国产91乱码一区二区三区_亚洲精品在线免费观看视频_欧美日韩亚洲国产综合_久久久久久久久久久成人_在线区

首頁 > 編程 > Delphi > 正文

Delphi中??考夹g(shù)的實(shí)現(xiàn)

2019-11-18 18:47:02
字體:
供稿:網(wǎng)友

隨著軟件技術(shù)的不斷進(jìn)步,軟件界面也越來越美觀,操作也越來越方便。

綜觀市面上比較專業(yè)的各種軟件,我們會(huì)發(fā)現(xiàn)大部分都提供窗體??康墓δ埽貏e象工具軟件,基本上都或多或少有停靠功能。

自然,Delphi也支持停靠,而且她和VCL緊密結(jié)合,對(duì)于廣大的Delphi程序員來說更是一大福音。讓我們省去枯燥的編碼時(shí)間。把注意力集中在核心程序的構(gòu)思上。

 

先讓我們來復(fù)習(xí)一下VCL的結(jié)構(gòu),在TWinControl類中有一個(gè)DockSite屬性(boolean),它的作用是是否允許別的控件??吭谒纳厦?,在TControl類中有一個(gè)DragKind屬性,如果要這個(gè)控件能??吭趧e的控件上,就把DragKind屬性設(shè)成dkDock。就這么簡(jiǎn)單,只要設(shè)置一下屬性,一個(gè)支持??康某绦蚓屯瓿闪?。

當(dāng)然,上面說的只是最最基本的步驟,有了以上兩步,我們就可以繼續(xù)編寫代碼實(shí)現(xiàn)更復(fù)雜的功能。

一般的支持??康某绦蚨伎梢栽谥鞔翱诘纳舷伦笥彝??,也就是說在主窗口的邊上放上能被??康目丶容^好(只要是從TWinControl繼承的都行),一般我們都選擇TPanel,為了便于讀者理解,我們可以假定主窗口的左邊可以??浚栽谥鞔翱谏戏乓粋€(gè)Align屬性為alLeftPanel,取名為LeftDockPanel,寬度為0,DockSite屬性為True,當(dāng)然我們的LeftDockPanel應(yīng)該是可以改變大小的,所以在它右邊再放一個(gè)TSplitter,取名為LeftSplitter,Align屬性為alLeft。接下來就是??靠丶?,一般的程序停靠控件都是窗體,所以我們也建一個(gè)窗體,取名叫DockableForm,DragKind屬性設(shè)成dkDock,DragMode屬性設(shè)為dmAutomatic(自動(dòng)停靠)

現(xiàn)在我們可以運(yùn)行這個(gè)程序了,什么?效果不好???康拇绑w??客?窟M(jìn)去后就不見了!

 

哦,我差點(diǎn)忘了,當(dāng)停靠窗體停靠時(shí)Delphi會(huì)產(chǎn)生一些事件,他們分別是

1OnDockOver(Sender: TObject; Source: TDragDockObject;

      X, Y: Integer; State: TDragState; var Accept: Boolean);

2OnDockDrop(Sender: TObject; Source: TDragDockObject;

      X, Y: Integer);

3OnGetSiteInfo(Sender: TObject; DockClient: TControl;

      var InfluenceRect: TRect; MousePos: TPoint; var CanDock: Boolean);

4OnStartDock(Sender: TObject;

      var DragObject: TDragDockObject);

5OnEndDock(Sender, Target: TObject; X, Y: Integer);

6OnUnDock(Sender: TObject; Client: TControl;

      NewTarget: TWinControl; var Allow: Boolean);

哇,這么多,別急,讓我細(xì)細(xì)道來:

先讓我們來看看第一個(gè)事件

OnDockOver是在??靠丶?/SPAN>(DockableForm)掠過被停靠控件(LeftDockPanel)時(shí)觸發(fā)的。Source包含了???/SPAN>拖動(dòng)操作的信息,其中有一個(gè)重要的屬性是Control,就是DockableForm,另一個(gè)重要的屬性是DockRect,就是停靠的位置;X,Y是鼠標(biāo)的位置,State的狀態(tài)有dsDragEnter, dsDragLeave, dsDragMove,分別表示拖動(dòng)進(jìn)入,拖動(dòng)離開,拖動(dòng)移動(dòng);Accept是是否同意??康囊馑?。OnDockOver事件主要作用是控制??看绑w的預(yù)覽位置,下面我們來加入以下代碼:

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

//修改預(yù)覽停靠位置

ARect.TopLeft := LeftDockPanel.ClientToScreen(Point(0, 0));

    ARect.BottomRight := LeftDockPanel.ClientToScreen(

      Point(Self.ClientWidth div 3, LeftDockPanel.Height));

    Source.DockRect := ARect;

  end;

end;

 

現(xiàn)在再運(yùn)行程序,當(dāng)你把DockableForm拖動(dòng)到主窗口左邊時(shí),已經(jīng)出現(xiàn)了預(yù)覽??课恢茫簿褪翘摼€包含的范圍。

怎么?窗體又不見了?那當(dāng)然了,我們只是講了OnDockOver,還沒詳細(xì)講解OnDockDrop呢,它才是決定??看绑w在哪里出現(xiàn)的罪魁禍?zhǔn)祝?/SPAN>

OnDockDrop(Sender: TObject;

  Source: TDragDockObject; X, Y: Integer);

參數(shù)和OnDockOver差不多,只是少了State: TDragStatevar Accept: Boolean

它是在停靠窗體進(jìn)入被停靠控件時(shí)發(fā)生的,作用是控制??看绑w的最終位置。下面添加如下代碼:

procedure TMainForm.LeftDockPanelDockDrop(Sender: TObject;

  Source: TDragDockObject; X, Y: Integer);

Begin

  LeftDockPanel.Width := ClientWidth div 3;

  LeftSplitter.Left := LeftDockPanel.Width + LeftSplitter.Width;

End;

現(xiàn)在再運(yùn)行程序,哇塞,成功了。出現(xiàn)了一個(gè)和DelphiIDE完全一樣的停靠窗體,上面是兩條橫線,用來把它拖出來,右上角有一個(gè)小X是用來關(guān)閉的。

不過好景不長(zhǎng),當(dāng)我們把它關(guān)閉時(shí),裝載DockableFormLeftDockPanel不能還原,還是霸占著主窗口的客戶區(qū),怎么辦?

嘻嘻,忘了告訴你們了,其實(shí)Delphi早就為我們作好了一切。

請(qǐng)打開DockableForm的關(guān)閉事件,你會(huì)發(fā)現(xiàn)原來當(dāng)你點(diǎn)擊右上角那個(gè)小X關(guān)閉DockableForm時(shí),它會(huì)觸發(fā)DockableFormOnClose事件,在OnClose事件中把LeftDockPanel的寬度設(shè)為0就行了。

procedure TDockableForm.FormClose(Sender: TObject;

  var Action: TCloseAction);

begin

  MainForm.LeftDockPanel.Width := 0;

  Action := caHide;

end;

 

以上所講的是如何在主窗口上??看绑w,原代碼都通過測(cè)試。同理,我們可以在主窗口的右邊,下邊,上邊都實(shí)現(xiàn)??抗δ堋?/SPAN>

對(duì)了,剛才我們只介紹了OnDockOverOnDockDrop,忘了介紹別的事件,下面簡(jiǎn)單介紹一下:

3OnGetSiteInfo(Sender: TObject; DockClient: TControl;

      var InfluenceRect: TRect; MousePos: TPoint; var CanDock: Boolean);

這個(gè)事件是在窗體移動(dòng)時(shí)觸發(fā)的,所以經(jīng)常觸發(fā),它里面的DockClient就是TDockableForm,

有一個(gè)引用參數(shù)叫CanDock,和OnDockOver中的Accept差不多,都是詢問是否允許停靠。在這里可以不寫,CanDock默認(rèn)就是True,也可以寫上CanDock := DockClient is TDockableForm;

 

4OnStartDock(Sender: TObject;

      var DragObject: TDragDockObject);

5OnEndDock(Sender, Target: TObject; X, Y: Integer);

6OnUnDock(Sender: TObject; Client: TControl;

      NewTarget: TWinControl; var Allow: Boolean);

這三個(gè)事件都是在DockableForm上面有用,意思分別是??块_始,??拷Y(jié)尾,不???/SPAN>(也就是被拖出來時(shí))。

OnStartDockOnEndDock經(jīng)常會(huì)被觸發(fā),

OnUnDock只在??看绑w變成浮動(dòng)時(shí)觸發(fā)

 

 

講了那么多,大家有沒有被搞糊涂?那好,我來做一下總結(jié):

Delphi中只要是從TWinControl繼承的控件都支持被???/SPAN>(如上面的LeftDockPanel),也就是有DockSite這個(gè)屬性;所有從TControl繼承的控件都支持???/SPAN>(如上面的DockableForm),也就是有DragKind這個(gè)屬性.所以支持被??康目丶贾С滞?浚С滞?康目丶灰欢ㄖС直煌??,道理很簡(jiǎn)單,因?yàn)?/SPAN>TWinControl繼承于TControlOnDockOver事件是控制??看绑w的預(yù)覽位置;OnDockDrap事件是控制??看绑w的最終位置;OnGetSiteInfo是詢問是否可以???;OnStartDock是??块_始,OnEndDock是停靠結(jié)尾,OnUnDock是不停靠(也就是被拖出來時(shí))

 

想必Delphi用的熟的大蝦都知道在Delphi的可停靠窗體間可以相互???,而且花樣還很多,可以??砍刹⑴诺模部梢酝?砍?/SPAN>PageControl樣式的,兩個(gè)可停靠窗體合并后的窗體又可以再和別的可??看绑w合并,形成樹狀。下面來介紹這方面的技術(shù):

說道這里,我們不得不介紹一下CM_DOCKCLIENT消息和TCMDockClient結(jié)構(gòu),

CM_DOCKCLIENT消息和TCMDockClient結(jié)構(gòu)是相互對(duì)應(yīng)的,TCMDockClient的結(jié)構(gòu)是:

  TCMDockClient = packed record

    Msg: Cardinal;

    DockSource: TDragDockObject;

    MousePos: TSmallPoint;

    Result: Integer;

  end;

其中DockSource包含了???/SPAN>拖動(dòng)操作的信息,前面已經(jīng)提到過;MousePos是鼠標(biāo)的位置。CM_DOCKCLIENT事件在停靠和被??靠丶伎梢圆东@,因?yàn)樗?/SPAN>TWinControl類發(fā)出的,

代碼如下:

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是先發(fā)送DOCKCLIENT消息,再觸發(fā)OnDockDrop事件的。

為了演示可??看绑w之間相互???,我們先創(chuàng)建一個(gè)宿主窗體,取名叫TiledHost,把它的DockSite設(shè)成True。它的作用是用來裝載兩個(gè)DockableForm的。

首先在DockableForm中捕獲DOCKCLIENT消息,在里面完成兩個(gè)窗體的相互???/SPAN>

聲明:

private

procedure CMDockClient(var Message: TCMDockClient); message CM_DOCKCLIENT;

end;

 

實(shí)現(xiàn):

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;

先解釋一下上面的代碼,首先創(chuàng)建TTiledHost的實(shí)例,然后用ManualDock函數(shù)把自己??康?/SPAN>TTiledHost,把Message.DockSource.Control也停靠到TTiledHost,這樣就完成了窗體的相互???,當(dāng)然,要是我們要程序產(chǎn)生停靠的預(yù)覽效果,就在DockableFormOnDockOver事件里加入代碼:

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;

 

怎么樣,效果還可以吧。對(duì)了,需要注意的是,用ManualDock函數(shù)可以安全的完成??抗δ?,不要用Dock函數(shù)。ManualDock函數(shù)有一些參數(shù):

function ManualDock(NewDockSite: TWinControl; DropControl: TControl = nil; ControlSide: TAlign = alNone): Boolean;

NewDockSite:要被??康拇绑w;

DropControl:已經(jīng)存在于NewDockSiteTControl,在這里可以把它設(shè)成nil;

ControlSide: ??康奈恢茫梢允巧?,下,左,右,全部等。

 

當(dāng)然,我們也可以讓TiledHost也具有和LeftDockPanel一樣有被停靠的功能,只要把TiledHost看成前面的LeftDockPanel,添加一些屬性和事件;把TiledHost看成DockableForm,

就可以有停靠的功能了。具體的做法這里不再闡述了,相信對(duì)VCL有深刻研究的大蝦都知道怎么做了。

 

 

下面我來講一下兩個(gè)窗體怎樣??砍?/SPAN>PageControl樣式。

首先創(chuàng)建一個(gè)窗體,叫TabHost,在它上面放一個(gè)PageControl,Align屬性設(shè)成alClient,讓它占滿整個(gè)TabHost,別忘了把PageControlDockSite屬性設(shè)成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封裝了一些對(duì)??康闹С?,它捕獲了CM_DOCKCLIENT

CM_DOCKNOTIFICATIONCM_UNDOCKCLIENT,WM_LBUTTONDBLCLK消息處理??縿?dòng)作。具體可以查看TPageControl的原代碼。

 

工具條的停靠也一樣,在主窗體上放一個(gè)ControlBarCoolBar,把他們的DockSite設(shè)成True;再在上面放ToolBar, ToolBarDragKind屬性設(shè)成dkDockDragMode屬性設(shè)為dmAutomatic。在這里,TControl有一個(gè)屬性叫FloatingDockSiteClass,它的類型是TWinControl的引用(class of TWinControl),只要在主窗口創(chuàng)建時(shí),把ToolBarFloatingDockSiteClass屬性設(shè)成某一個(gè)窗體A,比如在設(shè)計(jì)時(shí)A這個(gè)窗體叫ToolBarDockForm,但在程序里面不用顯式的創(chuàng)建ADelphi會(huì)自動(dòng)創(chuàng)建,當(dāng)ToolBar被拖動(dòng)出來時(shí),Delphi自動(dòng)把它裝載到ToolBarDockForm里,當(dāng)然ToolBarDockForm也要象上面提到的DockableForm一樣設(shè)置一定的屬性和添加一些代碼。

 

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

屬性:

1TControl. TBDockHeight               //存儲(chǔ)停靠控件在停靠時(shí)的的高度;

2TControl. LRDockWidth                //存儲(chǔ)??靠丶谕?繒r(shí)的的寬度;

3TControl. UnDockHeight               //存儲(chǔ)??靠丶诟?dòng)時(shí)的的高度;

4TControl. UnDockWidth                //存儲(chǔ)??靠丶诟?dòng)時(shí)的的寬度;

5TControl. HostDockSite           //存儲(chǔ)被??靠丶膶?shí)例

6TControl. FloatingDockSiteClass    //前面講過

7TControl. Floating                        //是否浮動(dòng)

9TControl. DockOrientation        //??靠丶姆轿?/SPAN>

10TWinControl .DockClientCount  //在這個(gè)控件里面有幾個(gè)已經(jīng)停靠的控件

11TWinControl . DockClients      //在這個(gè)控件里面有已經(jīng)??康目丶牧斜?/SPAN>

12TWinControl . DockManager    //一個(gè)控制??康念?,其實(shí)是一個(gè)ActiveX控件,和它對(duì)應(yīng)的類是TDockTree.

13. TWinControl .UseDockManager   //是否使用DockManager。


上一篇:用Delphi處理公歷到農(nóng)歷的轉(zhuǎn)換

下一篇:DELPHI與INTERNET2

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
學(xué)習(xí)交流
熱門圖片

新聞熱點(diǎn)

疑難解答

圖片精選

網(wǎng)友關(guān)注

主站蜘蛛池模板: 亚洲免费视频在线观看 | 亚洲国产精品一区 | 欧美日韩一区二区中文字幕 | 最新中文字幕在线 | 色欧美日韩 | 婷婷在线观看视频 | 日韩中文字幕在线观看 | 日本免费网站 | 日本三级在线视频 | 成人激情视频免费观看 | 天天干天天躁 | 九九热精品在线观看 | av成人在线观看 | 一级在线观看 | 国产超碰人人爽人人做人人爱 | 色噜| 亚洲一区二区三区免费在线观看 | 亚洲精品美女久久久 | 天天摸夜夜操 | 精品成人av| 黄色亚洲网站 | 伊人网av | 国产精品久久久久久 | 欧美一级欧美三级在线观看 | 国产日韩欧美在线 | 欧美激情a∨在线视频播放 欧美一级艳片视频免费观看 | 精品国产31久久久久久 | 国产精品成人免费一区二区视频 | 亚洲精品电影 | 成人免费视频视频在线观看 免费 | 欧美日韩在线观看中文字幕 | 中文av电影| 日批免费看 | 久久91精品 | 国产目拍亚洲精品99久久精品 | 久久久麻豆 | 91一区 | 久久精品网 | 欧美在线一二三 | 成人亚洲精品久久久久软件 | 青青艹在线视频 |