运行时动态移动控件的位置和改变控件的尺寸

Delphi的TCustomForm留有一个为IDE的可视化设计的用的接口Designer.
Designer是IDesignerNotify, IDesignerHook 接口.
我在这里实现了这些接口.
程序不用做任何改动,只要调函数BeginDesign就可以开始像IDE一样设计.EndDesign函数是结束设计.

{******************************************************************************
TFrom DesignHook接口的实现.

wr960204 武稀松
2007.9.10

******************************************************************************}

 {******************************************************************************
TFrom DesignHook接口的实现.

wyatt 修改 wr960204的代码

增加以下事件:

OnClick:单击鼠标事件

OnDbClick:双击鼠标事件

OnAddControl:增加控件时事件

使用方法,如对Form2进行设计:

kk:=TDesignerHook.Create(Form2,Form2);
KK.PopupMenu:=PopupMenu1;
KK.OnDbClick:=MyDb;
KK.OnAddControl:=OnAddC;
kk.OnClick:=OnClk;
kk.StartDesign;

开始进行设计

结束,使用kk.FinishDesign;

还在修改中


******************************************************************************}


unit DesignHookUtils;

interface
uses
Windows, SysUtils, Messages, Classes, Controls, Forms, ComObj, ActiveX,
Graphics,Dialogs,Menus;

const
GrabHandleSize = 4;

type
TMouseClick=procedure(Sender:TControl) of Object;
TAddControlEvent=procedure(Parent:TWinControl;Rect:TRect) of Object;

{
//开始设计.设计整个窗口里,以窗口为Owner的控件
function BeginDesign(Form: TCustomForm;OnUpdate:TMouseClick): IDesignerHook; overload;
//开始设计.设计窗口里,Root控件为Owner的控件
function BeginDesign(Form: TCustomForm; Root:TWinControl;OnUpdate:TMouseClick): IDesignerHook; overload;
//终止设计
procedure EndDesign(Form : TCustomForm);

}

type
TDesignerHook = class;

TCrackComponent = class(TComponent);
TCrackControl = class(TControl);

//管理FrameSize的.免得要遍历释放每个FrameSize
TGrabHandleManager = class(TComponent)
private
FDesigner: TDesignerHook;
public
constructor Create(ADesigner: TDesignerHook);
end;

//IDesignerHook的实现部分
TDesignerHook = class(TInterfacedObject, IDesignerNotify, IDesignerHook)
private
FGrabHandleManager: TGrabHandleManager;
FForm: TCustomForm;
FRoot: TWinControl;
FControls: TList;
FDraggingControl: TControl;
FDragging: Boolean;
FBeforDragPos: TPoint;

FSelecting: Boolean;
FPointStart, FPointEnd: TPoint;
FOldRect: TRect;
FNewRect: TRect;

FPopupMenu:TPopupMenu; //菜单事件
FOnClick:TMouseClick; //捕获鼠标单击事件
FOnDbClick:TMouseClick; //捕获鼠标双击事件
FOnAddControl:TAddControlEvent; //增加控件消息
FIsAddControl,FMouseAddDown:Boolean; //是否在添加控件


FMouseRect: TRect;//鼠标被限制的范围
procedure MouseLock(Sender: TControl);//锁定鼠标到某一个范围
procedure MouseFree();//释放对鼠标的锁定

function OnMessage(Sender: TControl; var Message: TMessage): Boolean;
procedure Remove(AControl: TControl); overload;
procedure Remove(Index: Integer); overload;
procedure Clear();
function Add(AControl: TControl): TControl;
procedure ShowGrabHandle(const Show: boolean);
procedure ClearGrabHandle(AControl: TControl);
procedure SetDragging(const Value: Boolean);
function GetControlCount: Integer;
function GetControls(Index: Integer): TControl;
procedure AddRectControls(Parent: TWinControl; Rect: TRect);
function OwnerCheck(Sender: TControl; CheckOnwer: TComponent): Boolean;

procedure MouseDown(Sender: TControl; Button: TMouseButton; Shift: TShiftState; X: Integer;
Y: Integer); virtual;
procedure MouseUp(Sender: TControl; Button: TMouseButton; Shift: TShiftState; X: Integer;
Y: Integer); virtual;
procedure MouseDbLclk(Sender: TControl; Button: TMouseButton; Shift: TShiftState; X: Integer;
Y: Integer); virtual;
procedure RightMouseUp(Sender: TControl; Button: TMouseButton; Shift: TShiftState; X: Integer;
Y: Integer); virtual;
procedure MouseMove(Sender: TControl; Shift: TShiftState; X: Integer; Y: Integer); virtual;
procedure KeyDown(Sender: TControl; var Key: Word; Shift: TShiftState); virtual;
procedure OnPopupMenuClick(Sender:TObject);virtual;
procedure CreateMenu;
public
constructor Create(InForm:TCustomForm;InWinControl:TWinControl);
destructor Destroy; override;

procedure StartDesign;
procedure FinishDesign;

property Dragging: Boolean read FDragging write SetDragging;
property ControlCount: Integer read GetControlCount;
property Controls[Index: Integer]: TControl read GetControls;
public
{ IDesignerNotify 的接口}

procedure Modified;
procedure Notification(AnObject: TPersistent; Operation: TOperation);
public
{ IDesignerHook 的接口}

function GetCustomForm: TCustomForm;
procedure SetCustomForm(Value: TCustomForm);
function GetRootForm: TWinControl;
procedure SetRootForm(Value: TWinControl);
function GetIsControl: Boolean;
procedure SetIsControl(Value: Boolean);
function IsDesignMsg(Sender: TControl; var Message: TMessage): Boolean;
procedure PaintGrid;
procedure PaintMenu;
procedure ValidateRename(AComponent: TComponent;
const CurName, NewName: string);
function UniqueName(const BaseName: string): string;
function GetRoot: TComponent;
procedure SetFoucs(Sender:TControl);
property AddControl:Boolean read FIsAddControl write FIsAddControl default False;
property IsControl: Boolean read GetIsControl write SetIsControl;
property Form: TCustomForm read GetCustomForm write SetCustomForm;
property Root: TWinControl read GetRootForm write SetRootForm;
property PopupMenu:TPopupMenu read FPopupMenu write FPopupMenu;
property OnDbClick:TMouseClick read FOnDbClick write FOnDbClick;
property OnClick:TMouseClick read FOnClick write FOnClick;
property OnAddControl:TAddControlEvent read FOnAddControl write FOnAddControl;
end;

//小黑点的方向性
TGrabHandleDirect = (fdLeftUp, fdUp, fdRightUp, fdRight,
fdRightDown, fdDown, fdLeftDown, fdLeft);

//就是选中时空间边上那八个小黑点
TGrabHandle = class(TCustomControl)
private
FHRgn: HRGN;
FManager: TGrabHandleManager;
FControl: TControl;
FDirect: TGrabHandleDirect;
FDesigner: TDesignerHook;
procedure Pos();
function GetDesigner: TDesignerHook;
protected
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X: Integer;
Y: Integer); override;
procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X: Integer;
Y: Integer); override;
procedure MouseMove(Shift: TShiftState; X: Integer; Y: Integer); override;

public
constructor Create(AManager: TComponent; AControl: TControl; ADirect: TGrabHandleDirect);
destructor Destroy; override;

property Designer: TDesignerHook read GetDesigner;

end;


var
ControlsList:TList;

implementation

//点到区的转化
function PointToRect(pt1, pt2: TPoint): TRect;
begin
if pt1.X < pt2.X then
begin
Result.Left := pt1.X;
Result.Right := pt2.X;
end
else
begin
Result.Left := pt2.X;
Result.Right := pt1.X;
end;
if pt1.Y < pt2.Y then
begin
Result.Top := pt1.Y;
Result.Bottom := pt2.Y;
end
else
begin
Result.Top := pt2.Y;
Result.Bottom := pt1.Y;
end;
end;

procedure EndDesign(Form : TCustomForm);
begin
TCrackComponent(Form).SetDesigning(False, True);
Form.Designer := nil;
ControlsList:=Nil;
Form.Invalidate;
end;

{ TDesignerHook }

function TDesignerHook.Add(AControl: TControl): TControl;
var
D : TGrabHandleDirect;
FrameSize : TGrabHandle;
begin
Result := AControl;
FControls.Add(AControl);
for D := fdLeftUp to fdLeft do
begin
FrameSize := TGrabHandle.Create(FGrabHandleManager, AControl, D);
end;

end;

procedure TDesignerHook.AddRectControls(Parent: TWinControl; Rect: TRect);
function InRect(R1, R2: TRect): Boolean;
begin
Result := False;
if not IntersectRect(R1, R1, R2) then
Exit;
Result := not IsRectEmpty(R1);
end;
var
I : Integer;
begin
Clear();

for I := 0 to Parent.ControlCount - 1 do
if InRect(Rect, Parent.Controls[I].BoundsRect) and
OwnerCheck(Parent.Controls[I], FRoot) then
begin
Add(Parent.Controls[I]);
end;
//如果没有选择控件,则选择主窗体
if ControlCount=0 then Add(Parent);

end;

procedure TDesignerHook.Clear;
var
I : Integer;
begin
for I := FControls.Count - 1 downto 0 do
Remove(I);
end;

procedure TDesignerHook.ClearGrabHandle(AControl: TControl);
var
I : Integer;
begin
for I := FGrabHandleManager.ComponentCount - 1 downto 0 do
if (FGrabHandleManager.Components[I] is TGrabHandle)
and (TGrabHandle(FGrabHandleManager.Components[I]).FControl = AControl) then
TGrabHandle(FGrabHandleManager.Components[I]).Free;
end;

constructor TDesignerHook.Create(InForm:TCustomForm;InWinControl:TWinControl);
begin
FGrabHandleManager := TGrabHandleManager.Create(Self);
FControls := TList.Create;

Form := InForm;
Root := InWinControl;
//建立菜单
CreateMenu;
end;

procedure TDesignerHook.OnPopupMenuClick(Sender:TObject);
var
I:Integer;
begin
if (ControlCount=0) or ((ControlCount = 1) and (Controls[0] = FForm)) then
Exit;

case TMenuItem(Sender).Tag of
1: //将所选择的控件置前
for I := ControlCount - 1 DownTo 0 do Controls[I].BringToFront;
2: //将所选择的控件置后
for I := ControlCount - 1 DownTo 0 do Controls[I].SendToBack;
end;
end;

procedure TDesignerHook.CreateMenu;
var
MenuItem,SubItem:TMenuItem;
begin
FPopupMenu:=TPopupMenu.Create(Nil);
MenuItem:=TMenuItem.Create(FpopupMenu);
MenuItem.Caption:='Control';
SubItem:=TMenuItem.Create(MenuItem);
SubItem.OnClick:=OnPopupMenuClick;
SubItem.Caption:='Bring to &Front';
SubItem.Tag:=1;
MenuItem.Add(SubItem);

SubItem:=TMenuItem.Create(MenuItem);
SubItem.OnClick:=OnPopupMenuClick;
SubItem.Tag:=2;
SubItem.Caption:='Send to &Back';
MenuItem.Add(SubItem);


FPopupMenu.Items.Add(MenuItem);
end;

destructor TDesignerHook.Destroy;
begin
if FForm <> nil then
TCrackComponent(FForm).SetDesigning(False, True);
FPopupMenu.Free;
FGrabHandleManager.Free;
FControls.Free;
inherited Destroy;
end;

procedure TDesignerHook.FinishDesign;
begin
TCrackComponent(Form).SetDesigning(False, True);
Form.Designer := nil;
Form.Invalidate;
end;

function TDesignerHook.GetControlCount: Integer;
begin
Result := FControls.Count;
end;

function TDesignerHook.GetControls(Index: Integer): TControl;
begin
Result := TControl(FControls[Index]);
end;

function TDesignerHook.GetCustomForm: TCustomForm;
begin
Result := FForm;
end;

function TDesignerHook.GetRootForm: TWinControl;
begin
Result :=FRoot;
end;

function TDesignerHook.GetIsControl: Boolean;
begin
Result := TCrackControl(FForm).IsControl;
end;

function TDesignerHook.GetRoot: TComponent;
begin
Result := FForm;
end;

function TDesignerHook.OnMessage(Sender: TControl;
var Message: TMessage): Boolean;
//var
// CtrlIndex, I : Integer;
begin
Result := ((Message.Msg >= WM_MOUSEFIRST) and (Message.Msg <= WM_MOUSELAST))
or ((Message.Msg >= WM_KEYFIRST) and (Message.Msg <= WM_KEYLAST));

case Message.Msg of
WM_LBUTTONDOWN:
MouseDown(
Sender,
mbLeft,
KeysToShiftState(TWMMouse(Message).Keys),
TWMMouse(Message).XPos,
TWMMouse(Message).YPos
);
WM_MOUSEMOVE:
begin
MouseMove(
Sender,
KeysToShiftState(TWMMouse(Message).Keys),
TWMMouse(Message).XPos,
TWMMouse(Message).YPos);

end;
WM_LBUTTONUP:
begin
MouseUp(
Sender,
mbLeft,
KeysToShiftState(TWMMouse(Message).Keys),
TWMMouse(Message).XPos,
TWMMouse(Message).YPos);
end;
WM_LBUTTONDBLCLK:
begin
MouseDbLclk(
Sender,
mbLeft,
KeysToShiftState(TWMMouse(Message).Keys),
TWMMouse(Message).XPos,
TWMMouse(Message).YPos);
end;

WM_RBUTTONUP:
begin
RightMouseUp(
Sender,
mbRight,
KeysToShiftState(TWMMouse(Message).Keys),
TWMMouse(Message).XPos,
TWMMouse(Message).YPos);
end;
WM_KEYDOWN:
begin
KeyDown(
Sender,
TWMKey(Message).CharCode,
KeyDataToShiftState(TWMKey(Message).KeyData)
);
end;
end;
if Sender = FForm then
Result := False;

end;

function TDesignerHook.IsDesignMsg(Sender: TControl;
var Message: TMessage): Boolean;
begin
Result := False;
if (Sender is TGrabHandle) then
Exit;

case Message.Msg of
WM_MOUSEFIRST..WM_MOUSELAST,
WM_KEYFIRST..WM_KEYLAST:
Result := OnMessage(Sender, Message);
end;
end;

procedure TDesignerHook.KeyDown(Sender: TControl; var Key: Word;
Shift: TShiftState);
var
I : Integer;
begin


if (ControlCount=0) or ((ControlCount = 1) and (Controls[0] = FForm)) then
Exit;

if ssCtrl in Shift then
begin
case Key of
VK_UP:
begin
ShowGrabHandle(False);
try
for I := 0 to ControlCount - 1 do
begin
Controls[I].Top := Controls[I].Top - 1;
end;
finally
ShowGrabHandle(True);
end;
end;
VK_DOWN:
begin
ShowGrabHandle(False);
try
for I := 0 to ControlCount - 1 do
begin
Controls[I].Top := Controls[I].Top + 1;
end;
finally
ShowGrabHandle(True);
end;
end;
VK_LEFT:
begin
ShowGrabHandle(False);
try
for I := 0 to ControlCount - 1 do
begin
Controls[I].Left := Controls[I].Left - 1;
end;
finally
ShowGrabHandle(True);
end;
end;
VK_RIGHT:
begin
ShowGrabHandle(False);
try
for I := 0 to ControlCount - 1 do
begin
Controls[I].Left := Controls[I].Left + 1;
end;
finally
ShowGrabHandle(True);
end;
end;
end;
end
else
begin
case Key of
VK_UP:
begin
ShowGrabHandle(False);
try
for I := 0 to ControlCount - 1 do
begin
if Controls[I].Height - 1 > 1 then
Controls[I].Height := Controls[I].Height - 1;
end;
finally
ShowGrabHandle(True);
end;
end;
VK_DOWN:
begin
ShowGrabHandle(False);
try
for I := 0 to ControlCount - 1 do
begin
if Controls[I].Height + 1 > 1 then
Controls[I].Height := Controls[I].Height + 1;
end;
finally
ShowGrabHandle(True);
end;
end;
VK_LEFT:
begin
ShowGrabHandle(False);
try
for I := 0 to ControlCount - 1 do
begin
if Controls[I].Width - 1 > 1 then

Controls[I].Width := Controls[I].Width - 1;
end;
finally
ShowGrabHandle(True);
end;
end;
VK_RIGHT:
begin
ShowGrabHandle(False);
try
for I := 0 to ControlCount - 1 do
begin
if Controls[I].Width + 1 > 1 then
Controls[I].Width := Controls[I].Width + 1;
end;
finally
ShowGrabHandle(True);
end;
end;
VK_DELETE:
begin
ShowGrabHandle(False);
for I := ControlCount - 1 DownTo 0 do
Controls[I].Free;
// FForm.RemoveControl(Controls[I]);
end;
end;
end;
end;

procedure TDesignerHook.Modified;
begin
end;

procedure TDesignerHook.MouseDown(Sender: TControl; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
CtrlIndex, I : Integer;
begin
if Dragging then
Exit;

CtrlIndex := FControls.IndexOf(Sender);

//鼠标单击事件
if Assigned(FOnClick) then FOnClick(Sender);

FMouseAddDown:=True;

if FIsAddControl and FMouseAddDown then //如果是新增加控件
begin
Clear;
MouseLock(Sender);
FPointStart := Sender.ClientToScreen(Point(X, Y));
FBeforDragPos := Sender.ClientToScreen(Point(X, Y));
FOldRect := Rect(X, Y, X + 1, Y + 1);
if Sender is TWinControl then
SetCaptureControl(Sender)
else if Sender.Parent<>Nil then
SetCaptureControl(Sender.Parent);

ShowGrabHandle(True);

Exit;
end;

if (ssShift in Shift) then //按Shift多选
begin
if (Sender = FRoot)or(Sender = FForm) then //多选不能添加Root或者Form
Exit;

if CtrlIndex = -1 then
begin
Add(Sender);
Dragging := False;
end
else
begin
Remove(Sender);
ShowGrabHandle(True);
end;
end
else
if (ssCtrl in Shift) or (Sender = FRoot) then //按住Ctrl或者点击的是Root就框选
begin
Clear();
if (Sender is TWinControl) then
begin
if (TWinControl(Sender).ControlCount = 0) then
begin
if CtrlIndex = -1 then
begin
Add(Sender);
ShowGrabHandle(True);
end;
end
else
begin
FPointStart := Sender.ClientToScreen(Point(X, Y));
FOldRect := Rect(X, Y, X + 1, Y + 1);
FSelecting := True;
SetCaptureControl(Sender);
end;
Exit;
end;
end
else //没按Shift也没按Ctrl点击.那就添加自己到选择的控件组中 .Root和Form不能和别的控件同时在组中
begin
begin
if (Sender = FRoot)or(Sender = FForm) then
Exit;
if CtrlIndex = -1 then
begin
Clear();
Add(Sender);
end;
end;

Dragging := True;
FDraggingControl := Sender;
MouseLock(Sender);
FBeforDragPos := Sender.ClientToScreen(Point(X, Y));
end;

end;

procedure TDesignerHook.MouseFree;
begin
SetCaptureControl(nil);
ClipCursor(@FMouseRect);
end;

procedure TDesignerHook.MouseLock(Sender: TControl);
var
R : TRect;
begin
SetCaptureControl(Sender);
GetClipCursor(FMouseRect);

if Sender.Parent = nil then
Exit;

R := Sender.Parent.ClientRect;
R.TopLeft := Sender.Parent.ClientToScreen(R.TopLeft);
R.BottomRight := Sender.Parent.ClientToScreen(R.BottomRight);
ClipCursor(@R); //把鼠标锁定在固定区域
end;

procedure TDesignerHook.MouseMove(Sender: TControl; Shift: TShiftState; X,
Y: Integer);
var
I : Integer;
CPos : TPoint;
DC : HDC;
begin

if FIsAddControl and FMouseAddDown then //新添加控件
begin
FPointEnd := Sender.ClientToScreen(Point(X, Y));
FNewRect := PointToRect(FPointStart, FPointEnd);

DC := GetDC(0);
DrawFocusRect(DC, FOldRect);
DrawFocusRect(DC, FNewRect);
ReleaseDC(0, DC);
FOldRect := FNewRect;
Exit;
end;

if Dragging then
begin
CPos := Mouse.CursorPos;
for I := FControls.Count - 1 downto 0 do
if Controls[I].Parent = Sender.Parent then //如果都是同一个Paren的话
begin
Controls[I].Left := Controls[I].Left - (FBeforDragPos.X - CPos.X);
Controls[I].Top := Controls[I].Top - (FBeforDragPos.Y - CPos.Y);
end
else
begin
Remove(I);
end;
FBeforDragPos := CPos;
end
else
if FSelecting then
begin
FPointEnd := Sender.ClientToScreen(Point(X, Y));
FNewRect := PointToRect(FPointStart, FPointEnd);

DC := GetDC(0);
DrawFocusRect(DC, FOldRect);
DrawFocusRect(DC, FNewRect);
ReleaseDC(0, DC);
FOldRect := FNewRect;

end;
end;

procedure TDesignerHook.MouseUp(Sender: TControl; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
DC : HDC;
begin
FMouseAddDown:=False;
if FIsAddControl then //新添加控件
begin
DC := GetDC(0);
DrawFocusRect(DC, FOldRect);
ReleaseDC(0, DC);
FIsAddControl := False;
FSelecting:=False;
SetCaptureControl(nil);

MouseFree;

FOldRect.TopLeft := Sender.ScreenToClient(FOldRect.TopLeft);
FOldRect.BottomRight := Sender.ScreenToClient(FOldRect.BottomRight);
FOldRect := PointToRect(FOldRect.TopLeft, FOldRect.BottomRight);

if Assigned(FOnAddControl) then
if Sender is TWinControl then
FOnAddControl(TWinControl(Sender),FOldRect)
else FOnAddControl(Sender.Parent,FOldRect);
ShowGrabHandle(True);
exit;
end;

if Dragging then
begin
MouseFree();
Dragging := False;
end;
if FSelecting then
begin
DC := GetDC(0);
DrawFocusRect(DC, FOldRect);
ReleaseDC(0, DC);
FSelecting := False;
SetCaptureControl(nil);
if Sender is TWinControl then
begin
FOldRect.TopLeft := Sender.ScreenToClient(FOldRect.TopLeft);
FOldRect.BottomRight := Sender.ScreenToClient(FOldRect.BottomRight);
FOldRect := PointToRect(FOldRect.TopLeft, FOldRect.BottomRight);
AddRectControls(TWinControl(Sender), FOldRect);
ShowGrabHandle(True);
end;
end;
//更新控件列表,为外部单元提供一些控制
ControlsList:=FControls;
FForm.Invalidate;
FForm.Update;
end;

procedure TDesignerHook.MouseDbLclk(Sender: TControl; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if Assigned(FOnDbClick) then FOnDbClick(Sender);
end;

procedure TDesignerHook.RightMouseUp(Sender: TControl; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
FPopupMenu.Popup(Sender.ClientToScreen(Point(X, Y)).X,Sender.ClientToScreen(Point(X, Y)).Y);
end;

procedure TDesignerHook.Notification(AnObject: TPersistent; Operation: TOperation);
var
Index : Integer;
begin
case Operation of
opRemove:
begin
Index := FControls.IndexOf(AnObject);
if Index <> -1 then
Remove(Index);
if AnObject = FForm then
begin
TCrackComponent(FForm).SetDesigning(False, True);
FForm := nil;
end;
end;
opInsert:
begin
end;
end;

end;

procedure TDesignerHook.PaintGrid;
begin

end;

procedure TDesignerHook.PaintMenu;
begin

end;

function TDesignerHook.OwnerCheck(Sender: TControl; CheckOnwer: TComponent): Boolean;
var
W : TComponent;
begin
Result := False;
W := Sender.Owner;
while W <> nil do
begin
if W = CheckOnwer then
begin
Result := True;
Exit;
end;
W := W.Owner;
end;
end;

procedure TDesignerHook.Remove(Index: Integer);
var
I : Integer;
Control : TControl;
begin
if Index = -1 then
Exit;
Control := TControl(FControls[Index]);
FControls.Delete(Index);
ClearGrabHandle(Control);
end;

procedure TDesignerHook.Remove(AControl: TControl);
begin
Remove(FControls.IndexOf(AControl));
end;

procedure TDesignerHook.SetCustomForm(Value: TCustomForm);
begin
FForm := Value;
if Value <> nil then
Value.Designer := Self;
end;

procedure TDesignerHook.SetRootForm(Value: TWinControl);
begin
FRoot := Value;
// if Value <> nil then
// Value.Designer := Self;
end;

procedure TDesignerHook.SetDragging(const Value: Boolean);
var
I : Integer;
begin
FDragging := Value;
ShowGrabHandle(not Value);
end;

procedure TDesignerHook.SetFoucs(Sender: TControl);
var
CtrlIndex, I : Integer;
begin

CtrlIndex := FControls.IndexOf(Sender);

//鼠标单击事件
if Assigned(FOnClick) then FOnClick(Sender);
Add(Sender);
ShowGrabHandle(True);
exit;
if CtrlIndex = -1 then
begin
Add(Sender);

end
else
begin
Remove(Sender);
ShowGrabHandle(True);
end;

end;

procedure TDesignerHook.SetIsControl(Value: Boolean);
begin
if FForm is TControl then
TCrackControl(FForm).IsControl := Value;
end;

procedure TDesignerHook.ShowGrabHandle(const Show: boolean);
var
I : Integer;
begin
for I := 0 to FGrabHandleManager.ComponentCount - 1 do
if (FGrabHandleManager.Components[I] is TGrabHandle)
then
begin
if ControlCount > 1 then
begin
TGrabHandle(FGrabHandleManager.Components[I]).Color := clAppWorkSpace;
end
else
begin
TGrabHandle(FGrabHandleManager.Components[I]).Color := clBlack;
end;

TGrabHandle(FGrabHandleManager.Components[I]).Pos();
TGrabHandle(FGrabHandleManager.Components[I]).Visible := Show and
((ControlCount = 1) or
((ControlCount > 1)
and (TGrabHandle(FGrabHandleManager.Components[I]).FDirect in [fdLeftUp, fdLeftDown, fdRightUp, fdRightDown])));
end;
end;

procedure TDesignerHook.StartDesign;
begin
Form.Designer := Self;
TCrackComponent(Form).SetDesigning(True, False);
TCrackComponent(Root).SetDesigning(True, True);
end;

function TDesignerHook.UniqueName(const BaseName: string): string;
var
guid : TGuid;
s : string;
begin
OleCheck(CoCreateGuid(guid));
s := GuidToString(guid);
s := Copy(s, 2, Length(s) - 2); //
s := StringReplace(s, '-', '', []);
Result := BaseName + s;
end;

procedure TDesignerHook.ValidateRename(AComponent: TComponent;
const CurName, NewName: string);
begin

end;

{ TGrabHandle }

constructor TGrabHandle.Create(AManager: TComponent; AControl: TControl; ADirect: TGrabHandleDirect);
begin
inherited Create(AManager);
FManager := TGrabHandleManager(AManager);
FDesigner := FManager.FDesigner;
Color := clYellow;
FDirect := ADirect;
FControl := AControl;
Visible := False;
Parent := AControl.Parent;
Pos();
end;

destructor TGrabHandle.Destroy;
begin

inherited Destroy;
end;

{
procedure TGrabHandle.CreateWnd(AManager: TComponent; AControl: TControl;
ADirect: TGrabHandleDirect);
begin
inherited Create(AManager);
ResetSize;
FManager := TGrabHandleManager(AManager);
FDesigner := FManager.FDesigner;
Color := clYellow;
FDirect := ADirect;
FControl := AControl;
Visible := False;
Parent := AControl.Parent;
Pos();
end;

procedure TGrabHandle.DestroyWnd;
begin
DeleteObject(FHRgn);
inherited;

end;

procedure TGrabHandle.Paint;
begin
inherited;
Canvas.Brush.Color := clyellow;
Canvas.Rectangle(ClientRect);
end;

procedure TGrabHandle.ResetSize;
begin
if FHRgn<>0 then DeleteObject(FHRgn);
FHrgn:=CreateRectRgn(ClientRect.Left, ClientRect.Top,
ClientRect.Right, ClientRect.Bottom);
SetWindowRgn(Handle, FHRgn, True);
end;
}
function TGrabHandle.GetDesigner: TDesignerHook;
begin
Result := FManager.FDesigner;
end;

procedure TGrabHandle.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
Y: Integer);
begin
inherited MouseDown(Button, Shift, X, Y);
if Designer.ControlCount > 1 then
Exit;
Designer.Dragging := True;
Designer.FBeforDragPos := ClientToScreen(Point(X, Y));
MouseCapture := True;
end;

procedure TGrabHandle.MouseMove(Shift: TShiftState; X, Y: Integer);
var
I : Integer;
CPos : TPoint;
cX, cY : Integer;
begin
inherited MouseMove(Shift, X, Y);
if not Designer.Dragging then
Exit;
CPos := ClientToScreen(Point(X, Y));
{
for I := 0 to Designer.ControlCount - 1 do
begin
Designer.Controls[I].Left := Designer.Controls[I].Left + (X - Designer.FBeforDragPos.X);
Designer.Controls[I].Top := Designer.Controls[I].Top + (Y - Designer.FBeforDragPos.Y);
end;
}
cX := Designer.FBeforDragPos.X - CPos.X;
cY := Designer.FBeforDragPos.Y - CPos.Y;
if (Abs(cX) < 2) and (Abs(cY) < 2) then
Exit;

case FDirect of
fdLeftUp:
begin
if FControl.Width + cX > 1 then
begin
FControl.Left := FControl.Left - cX;
FControl.Width := FControl.Width + cX;
Designer.FBeforDragPos.X := CPos.X;
end;
if FControl.Height + cY > 1 then
begin
FControl.Top := FControl.Top - cY;
FControl.Height := FControl.Height + cY;
Designer.FBeforDragPos.Y := CPos.Y;
end;
end;
fdUp:
begin
if FControl.Height + cY > 1 then
begin
FControl.Top := FControl.Top - cY;
FControl.Height := FControl.Height + cY;
Designer.FBeforDragPos.Y := CPos.Y;
end;
end;
fdRightUp:
begin
if FControl.Width - cX > 1 then
begin
FControl.Width := FControl.Width - cX;
Designer.FBeforDragPos.X := CPos.X;
end;
if FControl.Height + cY > 1 then
begin
FControl.Top := FControl.Top - cY;
FControl.Height := FControl.Height + cY;
Designer.FBeforDragPos.Y := CPos.Y;
end;
end;
fdRight:
begin
if FControl.Width - cX > 1 then
begin
FControl.Width := FControl.Width - cX;
Designer.FBeforDragPos.X := CPos.X;
end;
end;
fdRightDown:
begin
if FControl.Width - cX > 1 then
begin
FControl.Width := FControl.Width - cX;
Designer.FBeforDragPos.X := CPos.X;
end;
if FControl.Height - cY > 1 then
begin
FControl.Height := FControl.Height - cY;
Designer.FBeforDragPos.Y := CPos.Y;
end;
end;
fdDown:
begin
if FControl.Height - cY > 1 then
begin
FControl.Height := FControl.Height - cY;
Designer.FBeforDragPos.Y := CPos.Y;
end;
end;
fdLeftDown:
begin
if FControl.Width + cX > 1 then
begin
FControl.Left := FControl.Left - cX;
FControl.Width := FControl.Width + cX;
Designer.FBeforDragPos.X := CPos.X;
end;
if FControl.Height - cY > 1 then
begin
FControl.Height := FControl.Height - cY;
Designer.FBeforDragPos.Y := CPos.Y;
end;
end;
fdLeft:
begin
if FControl.Width + cX > 1 then
begin
FControl.Left := FControl.Left - cX;
FControl.Width := FControl.Width + cX;
Designer.FBeforDragPos.X := CPos.X;
end;
end;
end;

end;

procedure TGrabHandle.MouseUp(Button: TMouseButton; Shift: TShiftState; X,
Y: Integer);
begin
inherited MouseUp(Button, Shift, X, Y);
MouseCapture := False;
Designer.Dragging := False;
end;

procedure TGrabHandle.Pos();
var
X : array[0..2] of Integer;
Y : array[0..2] of Integer;
begin
X[0] := FControl.Left - GrabHandleSize div 2;
X[1] := FControl.Left + (FControl.Width - GrabHandleSize) div 2;
X[2] := FControl.Left + FControl.Width - GrabHandleSize div 2;
Y[0] := FControl.Top - GrabHandleSize div 2;
Y[1] := FControl.Top + (FControl.Height - GrabHandleSize) div 2;
Y[2] := FControl.Top + FControl.Height - GrabHandleSize div 2;
case FDirect of
fdLeftUp:
begin
Cursor := crSizeNWSE;
SetBounds(X[0], Y[0], GrabHandleSize, GrabHandleSize);
end;
fdUp:
begin
Cursor := crSizeNS;
SetBounds(X[1], Y[0], GrabHandleSize, GrabHandleSize);
end;
fdRightUp:
begin
Cursor := crSizeNESW;
SetBounds(X[2], Y[0], GrabHandleSize, GrabHandleSize);
end;
fdRight:
begin
Cursor := crSizeWE;
SetBounds(X[2], Y[1], GrabHandleSize, GrabHandleSize);
end;
fdRightDown:
begin
Cursor := crSizeNWSE;
SetBounds(X[2], Y[2], GrabHandleSize, GrabHandleSize);
end;
fdDown:
begin
Cursor := crSizeNS;
SetBounds(X[1], Y[2], GrabHandleSize, GrabHandleSize);
end;
fdLeftDown:
begin
Cursor := crSizeNESW;
SetBounds(X[0], Y[2], GrabHandleSize, GrabHandleSize);
end;
fdLeft:
begin
Cursor := crSizeWE;
SetBounds(X[0], Y[1], GrabHandleSize, GrabHandleSize);
end;
end;
if FDesigner.ControlCount > 1 then
Cursor := crDefault;
BringToFront;
end;


{ TGrabHandleManager }

constructor TGrabHandleManager.Create(ADesigner: TDesignerHook);
begin
inherited Create(nil);
FDesigner := ADesigner;
end;

end.

 
写了两个函数
在调用 BeginDesign 后调用 下 SvaeStateComps
在form Create时调用 RestoreStateComps
可实现保存和装载 Components 位置

procedure SaveStateComps(aForm: TCustomForm);
var i: Integer;
  oFName: string;
  ini: TIniFile;
  WC: TWinControl;
begin
  oFName := ExtractFilePath(ParamStr(0)); //(Application.ExeName);
  if oFName[Length(oFName)] <> '/' then
    oFName := oFName + '/';
  oFName := oFname + aForm.Name + '.GzFS';
  Ini := TIniFile.Create(oFName);
  try
    for i := aForm.ComponentCount - 1 downto 0 do
    begin
      if aForm.Components[i] is TWinControl then
      begin
        ini.WriteInteger(aForm.Components[i].Name, 'Left', TWinControl(aForm.Components[i]).Left);
        ini.WriteInteger(aForm.Components[i].Name, 'Top', TWinControl(aForm.Components[i]).Top);
        ini.WriteInteger(aForm.Components[i].Name, 'Width', TWinControl(aForm.Components[i]).Width);
        ini.WriteInteger(aForm.Components[i].Name, 'Height', TWinControl(aForm.Components[i]).Height);
      end;
    end;
  finally
    Ini.Free;
  end;
end;

procedure RestoreStateComps(aForm: tCustomForm);
var i: Integer;
  oFName: string;
  ini: TIniFile;
  WC: TWinControl;
begin
  oFName := ExtractFilePath(ParamStr(0));
  if oFName[Length(oFName)] <> '/' then
    oFName := oFName + '/';
  oFName := oFname + aForm.Name + '.GzFS';
  Ini := TIniFile.Create(oFName);
  try
    for i := aForm.ComponentCount - 1 downto 0 do
    begin
      if aForm.Components[i] is TWinControl then
      begin
        TWinControl(aForm.Components[i]).Left := ini.ReadInteger(aForm.Components[i].Name, 'Left', TWinControl(aForm.Components[i]).Left);
        TWinControl(aForm.Components[i]).Top := ini.ReadInteger(aForm.Components[i].Name, 'Top', TWinControl(aForm.Components[i]).Top);
        TWinControl(aForm.Components[i]).Width := ini.ReadInteger(aForm.Components[i].Name, 'Width', TWinControl(aForm.Components[i]).Width);
        TWinControl(aForm.Components[i]).Height := ini.ReadInteger(aForm.Components[i].Name, 'Height', TWinControl(aForm.Components[i]).Height);
      end;
    end;
  finally
    Ini.Free;
  end;
end; 

原文地址:https://www.cnblogs.com/hnxxcxg/p/2940884.html