📄 udockform.pas
字号:
unit uDockForm;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Menus,
ExtCtrls, StdCtrls, ComCtrls, Buttons;
type
TDockableForm = class(TForm)
Button1: TButton;
SpeedButton1: TSpeedButton;
PageControl1: TPageControl;
TabSheet1: TTabSheet;
TabSheet2: TTabSheet;
Panel1: TPanel;
CheckBox1: TCheckBox;
RadioButton1: TRadioButton;
RadioButton2: TRadioButton;
Memo1: TMemo;
procedure FormDockOver(Sender: TObject; Source: TDragDockObject; X,
Y: Integer; State: TDragState; var Accept: Boolean);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormShow(Sender: TObject);
private
function ComputeDockingRect(var DockRect: TRect; MousePos: TPoint): TAlign;
procedure CMDockClient(var Message: TCMDockClient); message CM_DOCKCLIENT;
public
end;
implementation
{$R *.dfm}
uses uTabHost, uConjoinHost, uMain;
procedure TDockableForm.FormDockOver(Sender: TObject;
Source: TDragDockObject; X, Y: Integer; State: TDragState;
var Accept: Boolean);
var
ARect: TRect;
begin
Accept := (Source.Control is TDockableForm);
//Draw dock preview depending on where the cursor is relative to our client area
if Accept and (ComputeDockingRect(ARect, Point(X, Y)) <> alNone) then
Source.DockRect := ARect;
end;
function TDockableForm.ComputeDockingRect(var DockRect: TRect; MousePos: TPoint): TAlign;
var
DockTopRect,
DockLeftRect,
DockBottomRect,
DockRightRect,
DockCenterRect: TRect;
begin
Result := alNone;
//divide form up into docking "Zones"
DockLeftRect.TopLeft := Point(0, 0);
DockLeftRect.BottomRight := Point(ClientWidth div 5, ClientHeight);
DockTopRect.TopLeft := Point(ClientWidth div 5, 0);
DockTopRect.BottomRight := Point(ClientWidth div 5 * 4, ClientHeight div 5);
DockRightRect.TopLeft := Point(ClientWidth div 5 * 4, 0);
DockRightRect.BottomRight := Point(ClientWidth, ClientHeight);
DockBottomRect.TopLeft := Point(ClientWidth div 5, ClientHeight div 5 * 4);
DockBottomRect.BottomRight := Point(ClientWidth div 5 * 4, ClientHeight);
DockCenterRect.TopLeft := Point(ClientWidth div 5, ClientHeight div 5);
DockCenterRect.BottomRight := Point(ClientWidth div 5 * 4, ClientHeight div 5 * 4);
//Find out where the mouse cursor is, to decide where to draw dock preview.
if PtInRect(DockLeftRect, MousePos) then
begin
Result := alLeft;
DockRect := DockLeftRect;
DockRect.Right := ClientWidth div 2;
end
else
if PtInRect(DockTopRect, MousePos) then
begin
Result := alTop;
DockRect := DockTopRect;
DockRect.Left := 0;
DockRect.Right := ClientWidth;
DockRect.Bottom := ClientHeight div 2;
end
else
if PtInRect(DockRightRect, MousePos) then
begin
Result := alRight;
DockRect := DockRightRect;
DockRect.Left := ClientWidth div 2;
end
else
if PtInRect(DockBottomRect, MousePos) then
begin
Result := alBottom;
DockRect := DockBottomRect;
DockRect.Left := 0;
DockRect.Right := ClientWidth;
DockRect.Top := ClientHeight div 2;
end
else
if PtInRect(DockCenterRect, MousePos) then
begin
Result := alClient;
DockRect := DockCenterRect;
end;
if Result = alNone then Exit;
//DockRect is in screen coordinates.
DockRect.TopLeft := ClientToScreen(DockRect.TopLeft);
DockRect.BottomRight := ClientToScreen(DockRect.BottomRight);
end;
procedure TDockableForm.FormClose(Sender: TObject;
var Action: TCloseAction);
begin
//the action taken depends on how the form is docked.
if (HostDockSite is TConjoinDockHost) then
begin
//remove the form's caption from the conjoin dock host's caption list
TConjoinDockHost(HostDockSite).UpdateCaption(Self);
//if we're the last visible form on a conjoined form, hide the form
if HostDockSite.VisibleDockClientCount <= 1 then
HostDockSite.Hide;
end;
//if docked to a panel, tell the panel to hide itself. If there are other
//visible dock clients on the panel, it ShowDockPanel won't allow it to
//be hidden
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
//Overriding this message allows the dock form to create host forms
//depending on the mouse position when docking occurs. If we don't override
//this message, the form will use VCL's default DockManager.
//NOTE: the only time ManualDock can be safely called during a drag
//operation is we override processing of CM_DOCKCLIENT.
if Message.DockSource.Control is TDockableForm then
begin
//Find out how to dock (Using a TAlign as the result of ComputeDockingRect)
Pt.x := Message.MousePos.x;
Pt.y := Message.MousePos.y;
DockType := ComputeDockingRect(ARect, Pt);
//if we are over a dockable form docked to a panel in the
//main window, manually dock the dragged form to the panel with
//the correct orientation.
if (HostDockSite is TPanel) then
begin
Message.DockSource.Control.ManualDock(HostDockSite, nil, DockType);
Exit;
end;
//alClient => Create a TabDockHost and manually dock both forms to the PageControl
//owned by the TabDockHost.
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
//if DockType <> alClient, create the ConjoinDockHost and manually dock both
//forms to it. Be sure to make dockable forms non-dockable when hosted by
// ConjoinDockForm, since it is using the VCL default DockManager.
else begin
Host := TConjoinDockHost.Create(Application);
Host.BoundsRect := Self.BoundsRect;
Self.ManualDock(Host, nil, alNone);
Self.DockSite := False;
Message.DockSource.Control.ManualDock(Host, nil, DockType);
TDockableForm(Message.DockSource.Control).DockSite := False;
Host.Visible := True;
end;
end;
end;
procedure TDockableForm.FormShow(Sender: TObject);
begin
if HostDockSite is TConjoinDockHost then
TConjoinDockHost(HostDockSite).UpdateCaption(nil);
if MainForm.skindata1.active then
MainForm.skindata1.skinform(handle);
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -