Function TDockableForm.ComputeDockingRect

. . . . . .

end;

procedure TDockableForm.FormClose(Sender: TObject;

var Action: TCloseAction);

begin

if (HostDockSite is TConjoinDockHost) then

if HostDockSite.VisibleDockClientCount <= 1

then HostDockSite.Hide;

if (HostDockSite is TPanel) then

MainForm.ShowDockPanel(HostDockSite as TPanel,

False, nil);

Action := caHide;

end;

procedure TDockableForm.CMDockClient(

var Message: TCMDockClient);

var ARect: TRect;

DockType: TAlign;

Host: TForm;

Pt: TPoint;

begin

if Message.DockSource.Control is TDockableForm then

begin

Pt.x := Message.MousePos.x;

Pt.y := Message.MousePos.y;

DockType := ComputeDockingRect(ARect, Pt);

if (HostDockSite is TPanel) then begin

Message.DockSource.Control.ManualDock(

HostDockSite, nil, DockType);

Exit;

end;

if DockType = alClient then begin

Host := TTabDockHost.Create(Application);

Host.BoundsRect := Self.BoundsRect;

Self.ManualDock(TTabDockHost(Host).PageControl1,

nil, alClient);

Message.DockSource.Control.ManualDock(

TTabDockHost(Host).PageControl1, nil, alClient);

Host.Visible := True;

end else begin

Host := TConjoinDockHost.Create(Application);

Host.BoundsRect := Self.BoundsRect;

Self.ManualDock(Host, nil, alNone);

Message.DockSource.Control.ManualDock(

Host, nil, DockType);

Host.Visible := True;

end;

end;

end;

End.

Процедура CMDockClient позволяет подключить к приложению новые доки из двух подключенных модулей. Если сообщение клиента о возможности присоединения было проигнорировано (в данном случае основной формой), то процедура CMDockClient строит с помощью объявленной вспомогательной переменной Host один из двух объявленных в модулях uConjoinHost и uTabHost новых доков и после дополнительных проверок пытается пристыковать клиентов с помощью нестандартных методов к этим докам. Может быть построено несколько таких доков. Один вариант формы-дока (форма-контейнер) объявлен в модуле, который приводится ниже.

unit uConjoinHost;

Interface

uses Windows, Messages, SysUtils, Classes, Graphics,

Controls, Forms, Dialogs, uDockForm;

Type

TConjoinDockHost = class(TForm)

procedure FormClose(Sender: TObject;

var Action: TCloseAction);

procedure FormDockDrop(Sender: TObject;

Source: TDragDockObject; X, Y: Integer);

procedure FormUnDock(Sender: TObject;

Client: TControl; NewTarget: TWinControl;

var Allow: Boolean);

procedure FormDockOver(Sender: TObject;

Source: TDragDockObject; X, Y: Integer;

State: TDragState; var Accept: Boolean);

procedure FormGetSiteInfo(Sender: TObject;

DockClient: TControl; var InfluenceRect: TRect;

MousePos: TPoint; var CanDock: Boolean);

private

procedure DoFloat(AControl: TControl);

end;

var ConjoinDockHost: TConjoinDockHost;

Implementation

{$R *.dfm}

procedure TConjoinDockHost.DoFloat(

AControl: TControl);

var ARect: TRect;

begin

ARect.TopLeft :=

AControl.ClientToScreen(Point(0, 0));

ARect.BottomRight := AControl.ClientToScreen(Point

(AControl.UndockWidth, AControl.UndockHeight));

AControl.ManualFloat(ARect);

end;

procedure TConjoinDockHost.FormClose(Sender: TObject;

var Action: TCloseAction);

begin

if DockClientCount = 1 then begin

DoFloat(DockClients[0]);

Action := caFree;

end else Action := caHide;

end;

procedure TConjoinDockHost.FormDockDrop(Sender:

TObject; Source: TDragDockObject; X, Y: Integer);

begin

DockManager.ResetBounds(True);

end;

procedure TConjoinDockHost.FormUnDock(Sender: TObject;

Client: TControl; NewTarget: TWinControl;

var Allow: Boolean);

begin

if Client is TDockableForm then

TDockableForm(Client).DockSite := True;

if (DockClientCount = 2) and (NewTarget <> Self)

then PostMessage(Self.Handle, WM_CLOSE, 0, 0);

end;

procedure TConjoinDockHost.FormDockOver(Sender:

TObject; Source: TDragDockObject; X, Y: Integer;

State: TDragState; var Accept: Boolean);

begin

Accept := Source.Control is TDockableForm;

end;

procedure TConjoinDockHost.FormGetSiteInfo(Sender:

TObject; DockClient: TControl; var InfluenceRect:

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

begin

CanDock := DockClient is TDockableForm;

end;

end.

Для формы-контейнера установлено: DockSite=true и UseDockManager=true(обязательно установить, иначе сгенерируется исключительная ситуация). На рис. 58 показан вариант пристыковки к форме-контейнеру трех клиентов.

Function TDockableForm.ComputeDockingRect - student2.ru

Рис. 58 Вариант 3 решения примера 24.

Последняя форма (TabDockHost) не может принимать клиентов – эту функцию выполняет расположенный на ней компонент PageControl1.у которого установленосвойство DockSite=true. Модуль, в котором эта форма объявлена, приводится ниже.

unit uTabHost;

Interface

uses Windows, Messages, SysUtils, Classes, Graphics,

Controls, Forms, Dialogs, ComCtrls;

Type

TTabDockHost = class(TForm)

PageControl1: TPageControl;

procedure FormClose(Sender: TObject;

var Action: TCloseAction);

procedure PageControl1UnDock(Sender: TObject;

Client: TControl; NewTarget: TWinControl;

var Allow: Boolean);

procedure PageControl1GetSiteInfo(Sender: TObject;

DockClient: TControl; var InfluenceRect: TRect;

MousePos: TPoint; var CanDock: Boolean);

procedure PageControl1DockOver(Sender: TObject;

Source: TDragDockObject; X, Y: Integer;

State: TDragState; var Accept: Boolean);

end;

var TabDockHost: TTabDockHost;

Implementation

{$R *.dfm}

uses uDockForm;

procedure TTabDockHost.FormClose(Sender: TObject;

var Action: TCloseAction);

var ARect: TRect;

begin

if PageControl1.DockClientCount = 1 then begin

with PageControl1.DockClients[0] do begin

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

ARect.BottomRight := ClientToScreen(

Point(UndockWidth, UndockHeight));

ManualFloat(ARect);

end;

Action := caFree;

end else Action := caHide;

end;

procedure TTabDockHost.PageControl1UnDock(Sender:

TObject; Client: TControl; NewTarget: TWinControl;

var Allow: Boolean);

begin

if (PageControl1.DockClientCount = 2) and

(NewTarget <> Self) then

PostMessage(Self.Handle, WM_CLOSE, 0, 0);

end;

procedure TTabDockHost.PageControl1GetSiteInfo(Sender:

TObject; DockClient: TControl; var InfluenceRect:

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

begin

CanDock := DockClient is TDockableForm;

end;

procedure TTabDockHost.PageControl1DockOver(Sender:

TObject; Source: TDragDockObject; X, Y: Integer;

State: TDragState; var Accept: Boolean);

begin

Accept := Source.Control is TDockableForm;

end;

End.

На рис. 59 отображена возможность применения формы “записная кижка” с пристыкованными к ней тремя формами (основная форма не показана). Естественно, страницы на форме можно переключать и, кроме того, делать на страницах какие-то записи.

Function TDockableForm.ComputeDockingRect - student2.ru

Рис. 59 Вариант 4 решения примера 24.

В заключение отметим использование функции ManualDock, которая может организовать технологию Drag and Dock в случаях отсутствия необходимых установок для двух стыкующихся элементов. В частности, в модуле uDockForm выполняется операция стыковки между основной формой и клиентом, при условии, что клиент запрашивает и получает прямоугольник “причаливания” в центре основной формы (задано программно: alClient в процедуре CMDockClient). Результат такой операции представлен на рис. 60. Окно в данном случае потеряло свои стандартные кнопки и стало неуправляемым с помощью мыши. Чтобы вернуть этому окну управление, как предусмотрено в приложении, необходимо обеспечить стыковку с ним еще одного клиента. В зависимости от варианта второй стыковки может быть получен один из двух случаев, представленных на рис. 58 и 59, которые получаются при обработке полученной операции с помощью похожих обработчиков, находящихся в модуле TConjoinDockHost (FormUnDock) и модуле TTabDockHost (PageControl1UnDock).

Function TDockableForm.ComputeDockingRect - student2.ru

Рис. 60 Вариант 5 решения примера 24.

Наши рекомендации