对于停靠技术,网络上已有大篇的文件在述说。比较:高级停靠(Dock)技术的实现 ,这个是实现最复杂的(个人认为)。当然,我所使用的方法是参考了 Using the TDockTabSet component by Jeremy North . 这个方法是使用了自Delphi2005之后出现的TDockTabSet控件,对于其使用方法,有兴趣的朋友可以在网上搜索下。
OK,下面来看下效果
接下来,就要到代码了。哈哈,大家关心的可能就是这个。不过在这之前你还是先把上面的那个“Using the TDockTabSet component by Jeremy North ”理解下.
代码实现其实很简单,我这里主要是使用接口及类封装
先看下接口部分
IDockForm
这个就是需要被显示的窗体需实现的接口。其实接口的方法,属性有些窗体本身的方法,属性已经实现了,必要的是(你只需要把下面的部分代码抄过去就OK了)
procedure TForm12.FormClose(Sender: TObject; var Action: TCloseAction);
begin
ManualFloat(Rect(0, 0, 0, 0));
Action := caFree;
end;
procedure TForm12.FormStartDock(Sender: TObject;
var DragObject: TDragDockObject);
begin
DragObject := TDragDockObjectEx.Create(Self);
DragObject.Brush.Color := clAqua;
end;
function TForm12.GetDockSite: TWinControl;
begin
Result := FDockSite;
end;
function TForm12.ManualDock(NewDockSite: TWinControl; DropControl: TControl;
ControlSide: TAlign): Boolean;
begin
Result := inherited ManualDock(NewDockSite, DropControl, ControlSide);
end;
procedure TForm12.SetBorderSytle(const Value: TFormBorderStyle);
begin
if BorderStyle <> Value then
BorderStyle:=Value;
end;
procedure TForm12.SetDockSite(const Value: TWinControl);
begin
FDockSite := Value;
end;
procedure TForm12.SetDragKind(const Value: TDragKind);
begin
if DragKind <> Value then
DragKind:=Value;
end;
procedure TForm12.SetDragMode2(const Value: TDragMode);
begin
if DragMode <> Value then
DragMode:=Value;
end;
IDockSite , IDockManagenmnet
这两个接口无需你来实现,它们是用来管理停靠和实现停靠位置的。
原理
首先创建的IDockManagenmnet 根据停靠的方位TDockSiteAlign,来创建停靠点IDockSite,有了停靠点就可以添加停靠窗体IDockForm了。
1、创建 DockManagenment
2、
3、
=============================代码实现部分(20100410放出)======================================
1、FunctionLibrary.UIDApi.Dock.pas 接口声明
{ --------------------------------窗体停止支持接口函数库概述--------------------------------
CreateTime : 2009-10-11
Platform : Windows 7 (7600.16385.090713-1255) 简体中文旗舰版
IDE : Embarcadero Delphi 2010 Version 14.0.3513.24210
Description : 函数库(FunctionLibrary.*.pas)是一些常函数单元文件,基于win7及
RAD2010的基础上开发,可能存在向下兼容的问题.
关于单元内变量,常量,类型及函数、过程的定义以"组"为标准,即作为同
一处理函数的数据定义在一起.
Example :
}
unit Core.Dock;
interface
uses
Forms,Controls,Classes;
type
TDockSiteAlign = (dsaLeft,dsaBottom,dsaRight);
IDockForm = interface
['{FFE9B72A-EEBD-4201-9346-98D513F0E207}']
procedure SetBorderSytle(const Value:TFormBorderStyle);
property BorderStyle:TFormBorderStyle write SetBorderSytle;
procedure SetDragKind(const Value:TDragKind);
property DragKind:TDragKind write SetDragKind;
procedure SetDragMode2(const Value:TDragMode);
property DragMode:TDragMode write SetDragMode2;
function GetDockSite:TWinControl;
procedure SetDockSite(const Value:TWinControl);
property DockSite:TWinControl read GetDockSite write SetDockSite;
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormStartDock(Sender: TObject; var DragObject: TDragDockObject);
function ManualDock(NewDockSite: TWinControl; DropControl: TControl = nil;
ControlSide: TAlign = alNone): Boolean;
procedure Show;
procedure Close;
end;
IDockSite = interface
['{CDD2B1D8-63AE-494A-85A1-768D34D970A4}']
function AddDockForm(const DockForm:IDockForm):Boolean;
function GetVisible:Boolean;
procedure SetVisible(const Value:Boolean);
property Visible:Boolean read GetVisible write SetVisible;
function GetWidth:Integer;
procedure SetWidth(const Value:Integer);
property Width:Integer read GetWidth write SetWidth;
procedure SetAlign(const Value:TDockSiteAlign);
property Align:TDockSiteAlign write SetAlign;
end;
IDockManagemnet = interface
['{3754DE0D-425B-4A43-AF02-616A1A5C46EC}']
function AddDockSite(const Align:TDockSiteAlign):IDockSite;
function GetDockSite(const Align:TDockSiteAlign):IDockSite;
end;
const
DockFormGUID:TGUID='{FFE9B72A-EEBD-4201-9346-98D513F0E207}';
implementation
end.
2、FunctionLibrary.UIDApi.Impl.pas 接口实现
{ --------------------------------窗体停止支持主程序实现函数库概述--------------------------------
CreateTime : 2009-10-11
Platform : Windows 7 (7600.16385.090713-1255) 简体中文旗舰版
IDE : Embarcadero Delphi 2010 Version 14.0.3513.24210
Description : 函数库(FunctionLibrary.*.pas)是一些常函数单元文件,基于win7及
RAD2010的基础上开发,可能存在向下兼容的问题.
关于单元内变量,常量,类型及函数、过程的定义以"组"为标准,即作为同
一处理函数的数据定义在一起.
Example :
}
unit Core.Dock.Impl;
interface
uses
FunctionLibrary.UIDApi.Dock, Classes, Controls,
DockTabSet, ExtCtrls, Tabs, ComCtrls, Types, SysUtils;
type
TDockSiteControl = class
strict private
FOwner: IDockSite;
FDockTabSet: TDockTabSet;
FDockSplitter: TSplitter;
FDockPanel: TPanel;
procedure SetDockPanel(const Value: TPanel);
procedure SetDockSplitter(const Value: TSplitter);
procedure SetDockTabSet(const Value: TDockTabSet);
public
constructor Create(const AOwner: IDockSite);
destructor Destroy; override;
property DockTabSet: TDockTabSet read FDockTabSet write SetDockTabSet;
property DockPanel: TPanel read FDockPanel write SetDockPanel;
property DockSplitter: TSplitter read FDockSplitter write SetDockSplitter;
end;
TDockSite = class(TInterfacedObject, IDockSite)
strict private
FOwner: IDockManagemnet;
FHost:TWinControl;
FVisible: Boolean;
FWidth: Integer;
FDockSiteControl: TDockSiteControl;
FAlign: TDockSiteAlign;
FCount: Integer;
FDockFormList: array of IDockForm;
function GetDockFormIndex(const DockForm: IDockForm): Integer;
// Events for inner controls
procedure OnDockTabSetTabAdded(Sender: TObject);
procedure OnDockPanelDockDrop(Sender: TObject; Source: TDragDockObject;
X, Y: Integer);
procedure OnDockPanelUnDock(Sender: TObject; Client: TControl;
NewTarget: TWinControl; var Allow: Boolean);
procedure OnDockPanelDockOver(Sender: TObject; Source: TDragDockObject;
X, Y: Integer; State: TDragState; var Accept: Boolean);
procedure OnDockTabSetDragDrop(Sender, Source: TObject; X, Y: Integer);
procedure OnDockTabSetTabRemoved(Sender: TObject);
strict protected
function GetVisible: Boolean;
function GetWidth: Integer;
procedure SetVisible(const Value: Boolean);
procedure SetWidth(const Value: Integer);
procedure SetAlign(const Value: TDockSiteAlign);
public
constructor Create(const AOwner: IDockManagemnet; const Host: TWinControl);
destructor Destroy; override;
function AddDockForm(const DockForm: IDockForm): Boolean;
end;
TDockManagement = class(TInterfacedObject, IDockManagemnet)
strict private
FAOwner: TComponent;
DockSiteList: array [TDockSiteAlign] of IDockSite;
public
constructor Create(AOwner: TComponent);
destructor Destroy; override;
function AddDockSite(const Align: TDockSiteAlign): IDockSite;
function GetDockSite(const Align: TDockSiteAlign): IDockSite;
end;
implementation
{$REGION ' TDockManagement '}
{ TDockManagement }
function TDockManagement.AddDockSite(const Align: TDockSiteAlign): IDockSite;
begin
if Assigned(DockSiteList[Align]) then
Exit(DockSiteList[Align]);
Result := TDockSite.Create(Self, TWinControl(FAOwner));
DockSiteList[Align] := Result;
Result.Align := Align;
end;
constructor TDockManagement.Create(AOwner: TComponent);
begin
FAOwner := AOwner;
end;
destructor TDockManagement.Destroy;
begin
DockSiteList[dsaRight] := nil;
DockSiteList[dsaLeft] := nil;
DockSiteList[dsaBottom] := nil;
FAOwner := nil;
inherited;
end;
function TDockManagement.GetDockSite(const Align: TDockSiteAlign): IDockSite;
begin
Result := nil;
if Assigned(DockSiteList[Align]) then
Result := DockSiteList[Align];
end;
{$ENDREGION}
{ TDockSite }
function TDockSite.AddDockForm(const DockForm: IDockForm): Boolean;
var
Len, Index: Integer;
begin
Result := False;
Index := GetDockFormIndex(DockForm);
if Index > -1 then
Exit;
DockForm.DockSite := FDockSiteControl.DockPanel;
Len := Length(FDockFormList);
if Len = 0 then
SetLength(FDockFormList, 4)
else if Len = FCount then
SetLength(FDockFormList, Len * 2);
FDockFormList[FCount] := DockForm;
Inc(FCount);
Result := True;
end;
constructor TDockSite.Create(const AOwner: IDockManagemnet;
const Host: TWinControl);
begin
FDockSiteControl := TDockSiteControl.Create(Self);
FOwner := AOwner;
FHost:=Host;
with FDockSiteControl do
begin
DockTabSet := TDockTabSet.Create(Host);
with DockTabSet do
begin
Parent := TWinControl(Host);
Visible := False;
DockSite := False;
ShrinkToFit := True;
Style := tsModernTabs;
DestinationDockSite := nil;
OnDragDrop := OnDockTabSetDragDrop;
OnTabRemoved := OnDockTabSetTabRemoved;
OnTabAdded:=OnDockTabSetTabAdded;
end;
DockPanel := TPanel.Create(Host);
with DockPanel do
begin
Parent := TWinControl(Host);
Caption := '';
Visible := False;
Width := 0;
BevelOuter := bvNone;
DockSite := True;
OnDockDrop := OnDockPanelDockDrop;
onDockOver := OnDockPanelDockOver;
OnUnDock := OnDockPanelUnDock;
end;
DockTabSet.DestinationDockSite := DockPanel;
DockSplitter := TSplitter.Create(Host);
with DockSplitter do
begin
Parent := TWinControl(Host);
Visible := False;
Width := 4;
end;
end;
end;
destructor TDockSite.Destroy;
var
Item: IDockForm;
begin
for Item in FDockFormList do
if Assigned(Item) then
Item.Close;
SetLength(FDockFormList, 0);
FDockSiteControl.Free;
FOwner := nil;
FHost:=nil;
inherited;
end;
procedure TDockSite.OnDockTabSetTabAdded(Sender: TObject);
begin
FDockSiteControl.DockTabSet.Visible:=True;
end;
function TDockSite.GetDockFormIndex(const DockForm: IDockForm): Integer;
var
i: Integer;
begin
Result := -1;
for i := 0 to FCount - 1 do
if FDockFormList[i] = DockForm then
Result := i;
end;
function TDockSite.GetVisible: Boolean;
begin
Result := FVisible;
end;
function TDockSite.GetWidth: Integer;
begin
Result := FWidth;
end;
procedure TDockSite.OnDockPanelDockDrop
(Sender: TObject; Source: TDragDockObject; X, Y: Integer);
begin
with FDockSiteControl do
begin
if not DockPanel.Visible then
DockPanel.Visible:=True;
case FAlign of
dsaLeft, dsaRight:
begin
if DockPanel.Width = 0 then
DockPanel.Width := FWidth;
end;
dsaBottom:
begin
if DockPanel.Height = 0 then
DockPanel.Height := FWidth;
end;
end;
case FAlign of
dsaBottom:
begin
DockPanel.Top:=DockTabSet.Top - DockPanel.Height;
DockSplitter.Top:=DockPanel.Height - 4;
end;
dsaLeft:
begin
DockPanel.Left:=DockTabSet.Width;
DockSplitter.Left:=DockPanel.Width + DockPanel.Left;
end;
dsaRight:
begin
DockPanel.Left:=DockTabSet.Left - DockPanel.Width;
DockSplitter.Left:=DockPanel.Left - 4;
end;
end;
DockSplitter.Visible := True;
end;
end;
procedure TDockSite.OnDockPanelDockOver
(Sender: TObject; Source: TDragDockObject; X, Y: Integer; State: TDragState;
var Accept: Boolean);
var
lRect: TRect;
begin
Accept := Supports(Source.Control, DockFormGUID);
if Accept then
begin
with FDockSiteControl do
begin
case FAlign of
dsaLeft:
begin
lRect.TopLeft := DockPanel.ClientToScreen(Point(0, 0));
lRect.BottomRight := DockPanel.ClientToScreen(Point(150,DockPanel.Height));
end;
dsaBottom:
begin
lRect.TopLeft := DockPanel.ClientToScreen(Point(0, 0));
lRect.BottomRight := DockPanel.ClientToScreen(Point(DockPanel.Width,-150));
end;
dsaRight:
begin
lRect.TopLeft := DockPanel.ClientToScreen(Point(-150,0));
lRect.BottomRight := DockPanel.ClientToScreen(Point(0 ,DockPanel.Height));
end;
end;
end;
Source.DockRect := lRect;
end;
end;
procedure TDockSite.OnDockPanelUnDock(Sender: TObject; Client: TControl;
NewTarget: TWinControl; var Allow: Boolean);
begin
with FDockSiteControl do
begin
if DockPanel.DockClientCount = 1 then
begin
case FAlign of
dsaLeft, dsaRight:
DockPanel.Width := 0;
dsaBottom:
DockPanel.Height := 0;
end;
DockSplitter.Visible := False;
end;
end;
end;
procedure TDockSite.OnDockTabSetDragDrop(Sender, Source: TObject;
X, Y: Integer);
begin
FDockSiteControl.DockTabSet.Visible := True;
end;
procedure TDockSite.OnDockTabSetTabRemoved(Sender: TObject);
begin
FDockSiteControl.DockTabSet.Visible :=
FDockSiteControl.DockTabSet.Tabs.Count > 0;
end;
procedure TDockSite.SetAlign(const Value: TDockSiteAlign);
procedure SetControlAlign(const Alg: TAlign);
begin
with FDockSiteControl do
begin
with DockTabSet do
begin
Align := Alg;
case Alg of
alBottom:
begin
TabPosition := tpBottom;
DockPanel.Top:=Top - DockPanel.Height;
DockSplitter.Top:=DockPanel.Height - 4;
end;
alLeft:
begin
TabPosition := tpLeft;
DockPanel.Left:=Width;
DockSplitter.Left:=DockPanel.Width + DockPanel.Left;
end;
alRight:
begin
TabPosition := tpRight;
DockPanel.Left:=Left - DockPanel.Width;
DockSplitter.Left:=DockPanel.Left - 4;
end;
end;
DockPanel.Align := Alg;
DockSplitter.Align := Alg;
end;
end;
end;
begin
if FAlign <> Value then
FAlign := Value;
with FDockSiteControl do
begin
case Value of
dsaLeft:
begin
DockTabSet.Width := 25;
SetControlAlign(alLeft);
end;
dsaBottom:
begin
DockTabSet.Height := 25;
DockPanel.Height := 0;
SetControlAlign(alBottom);
end;
dsaRight:
begin
DockTabSet.Width := 25;
SetControlAlign(alRight);
end;
end;
end;
end;
procedure TDockSite.SetVisible(const Value: Boolean);
begin
if FVisible <> Value then
begin
FVisible := Value;
with FDockSiteControl do
begin
DockTabSet.Visible := Value;
DockPanel.Visible := Value;
// DockSplitter.Visible := Value;
end;
end;
end;
procedure TDockSite.SetWidth(const Value: Integer);
begin
if FWidth <> Value then
FWidth := Value;
end;
{$REGION ' TDockSiteControl '}
{ TDockSiteControl }
constructor TDockSiteControl.Create(const AOwner: IDockSite);
begin
FOwner := AOwner;
end;
destructor TDockSiteControl.Destroy;
begin
FOwner := nil;
if Assigned(FDockPanel) then
FDockPanel.Free;
if Assigned(FDockTabSet) then
FDockTabSet.Free;
if Assigned(FDockSplitter) then
FDockSplitter.Free;
inherited;
end;
procedure TDockSiteControl.SetDockPanel(const Value: TPanel);
begin
FDockPanel := Value;
end;
procedure TDockSiteControl.SetDockSplitter(const Value: TSplitter);
begin
FDockSplitter := Value;
end;
procedure TDockSiteControl.SetDockTabSet(const Value: TDockTabSet);
begin
FDockTabSet := Value;
end;
{$ENDREGION}
end.