Delphi的IDE是本身就是一個非常精彩的軟件,其中涵含了許多非常寶貴的軟件知識。IDE中有一個窗體設計器,控件放在裏面,就可以隨意移動,以及調整大小,如果能夠自己實現一個類似於這樣的窗體設計器,那真是一件非常美妙事情。本文實現的就是窗體設計器中最重要的部分,一個移動控件的類,控件要求從TControl繼承下來,在介紹如何實現之前,先說說這個類的用法:
其中有兩個類:
TDragClass就是實現拉動的類
TDragPoint是控件周圍出現的拉動點的類
用法很簡單:
創建一個TDragClass對象
將要實現拉動的控件傳進去就行了
比如:
myDrag.addControl(Edit1);
這樣Edit1就能實現拉動和移動了。
另外有兩個屬性來控制移動的方式
isMoveStep:boolean
指定移動的方式,True爲跳躍式,False爲連續式,默認情況下是False,即連續式。
所謂跳躍式,即移動或拉動控件時,控件是以離散的方式在改變自己的位置和大小的,這個對窗體設計器中的控件對齊有幫助。而連續式,當然就是以連續的方式使控件的位置和大小得到改變。
MoveStep :integer
當移動方式爲跳躍式時,該屬性指定跳躍的大小,範圍在5-20之間
另外還有一個方法:SetPointVisible(value:Boolean);用於指定移動點的可見性。在Delphi中,當你點擊窗口時,控件周圍的八個小點就消失了,即用此原理。
現在開始進入到具體實現的部分了,當你點擊Delphi的窗體設計器中的控件時,控件周圍出現了八個小點,這八個小點其實也是窗口類: TGrabHandle。預想中要實現控件移動,得有一個標識你正在移動或拉動的東西,這八個小點正是,Delphi的這種做法可以借鑑。於是我實現了一個移動點類:TDragPoint,該的對象將作爲TDragClass的成員之一,具體等一下再講。現在來看它的實現,其實非常簡單,因爲VCL給了我們一個有自繪能力的類TCustomControl,只要從這裏繼承下來,再重載其中的Paint方法,自己來畫這個移動點就行了。
代碼非常簡單,這裏就不多說了:
//---------TDragPoint--------------------------
unit UDragPoint;
interface
uses Windows, Messages,Controls,Classes,Graphics;
type
TDragPoint=class(TCustomControl)
protected
procedure Paint;override;
public
//處理移動時用變量
isDown:Boolean;
PrevP,NextP:TPoint;
constructor Create(AOwner: TComponent); override;
procedure CreateWnd; override;
published
property OnMouseMove;
property OnMouseDown;
property OnMouseUp;
end;
implementation
{ TDragPoint }
constructor TDragPoint.create;
begin
inherited Create(AOwner);
isDown:=False;
Width:=6;
Height:=6;
end;
procedure TDragPoint.CreateWnd;
begin
inherited;
//使該類位窗口最前
BringWindowToTop(self.Handle);
end;
procedure TDragPoint.Paint;
begin
Canvas.Brush.Color:=clBlack;
Canvas.Brush.Style:=bsSolid;
Canvas.Rectangle(0,0,width,Height);
end;
end.
這裏有必須談到的一點是該類重載了WndCreate,並在其中寫入BringWindowToTop(self.Handle);這樣做目的是讓這些移動點控件能夠位於窗口的最前位置。另外在其中顯化了三個鼠標事件:
property OnMouseMove;
property OnMouseDown;
property OnMouseUp;
目的是爲了在TDragClass中實現移動這些點。
現在可以進入主題,來說明TDragClass的實現了。
其中有一個保存傳進來的控件的列表類:FConList:TList;還有一個標識當前正在被移動或拉動的控件在FConList中的索引FCurActiveCon:Integer;
還有控件事件相關的成員
FConMouseDown:TMouseEvent;
FConMouseMove:TMouseMoveEvent;
FConMouseup:TMouseEvent;
這三個事件方法指針指向所有傳進來的控件的鼠標事件的處理函數,在Create中將得到賦值。而所有控件的鼠標處理函數將在類中實現。
接下來就到了最重要的成員了:FPointRec:TPointRec;這是一個記錄類型,其定義爲:
TPointRec=record
LeftTop:TDragPoint;
LeftBottom:TDragPoint;
RightTop:TDragPoint;
RightButton:TDragPoint;
LeftMid:TDragPoint;
TopMid:TDragPoint;
RightMid:TDragPoint;
ButtonMid:TDragPoint;
end;
這正是當前被移動控件邊緣的八個點。這八個點會粘在被移動控件的邊緣。
上面說過該類可以實現跳躍式移動或拉動則必定有相關的成員: FisMoveStep:Boolean;
FMoveStep:integer;
MoveX,MoveY:integer;
FisMoveStep指定是否爲跳躍式,FMoveStep爲跳躍的幅度,MoveX,MoveY標識控件移動或拉動的距離是否達到了FMoveStep,是就改變控件位置和大小,如此重複
除了上面那些成員,類中還定義了一些相類的方法,大概如下:
//-------對移動點類的操作—
//創建移動點類
procedure CreateDragPoint(PointParent:TWinControl);
//設定移動點類的位置
procedure SetPointPos(posRect:TRect);
//指定移動點類的父窗口
procedure SetPointParent(PointParent:TWinControl);
//設置移動點類的鼠標事件
procedure SetPointEvent;
//設置移動點類的可見性
procedure SetPointVisible(Visibled:Boolean);
//三個控件事件處理函數,所有控件的鼠標處理函數都將是這個,主要是解決控件的移動
//以及移動點類的位置,當你點擊某一個控件的時候,移動點類會附着到這個控件的邊緣
procedure ConMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure ConMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure ConMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
//移動點類的鼠標處理事件,解決移動點類的移動,以及當前控件的大小改變
procedure PointMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure PointMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure PointMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
最後一個重要方法是function addControl(AddCon:Pointer):Boolean;
控件從這裏加入,就可以實現移動和拉動了。
下面就將類實現比較重要的幾點略說一下吧(主要還是看代碼吧)
在類的構造函數中,將上面的三個控件處理函數指定給三個指針成員:
FConMouseDown:=ConMouseDown;
FConMouseMove:=ConMouseMove;
FConMouseup:=ConMouseUp;
現在這三個成員就指定了三個處理函數的地址了,等一下就可以看到那些控件的鼠標消息是怎麼和這三個處理函數聯繫在一起的,實現就在AddControl函數中。
AddControl是一個非常重要的方法,在控件加入之前,它要先判斷控件是否有Parent值,沒有則不能加入,更重要的一點是,在FConList是否已經有這個控件了,即該控件已經加入過了,如果已經加入了,則不能再加一次,代碼如下:
//如果該控件已經在列表中了,則加入失敗
for i:=0 to FConList.Count-1 do
if Integer(AddCon)=Integer(FConList.Items[i]) then
begin
result:=false;
exit;
end;
如果可以加入則先加入列表類中,再指定當前活動控件:
FConList.Add(AddCon);
FCurActiveCon:=FConList.Count-1;
而AddControl中還有一個比較重要的TempCon.Parent.DoubleBuffered:=True;
即加入的控件的父窗口設爲雙緩衝模式,這樣在移動控件或拉動控件大小的時候,不會出現閃爍現象。
接着就是爲加入的控件指定鼠標處理函數了,但加入的是TControl,而他的鼠標事件指針被設爲保護類型,因此無法獲得,但他的子類把他們顯化出來了。這裏用了一種折衷的方案:
TButton(TempCon).OnMouseDown:=FconMouseDown;
TButton(TempCon).OnMouseMove:=FconMouseMove;
TButton(TempCon).OnMouseUp:=FconMouseUp;
這樣做並不會出錯,但顯得怪怪的,但不理他了,能實現功能就行了。現在加入控件的鼠標事件都將會在這裏的三個處理函數中處理了。
最後,將移動點類移動該控件的邊緣去。
說得夠雜的,各位可以和第二部分的原代碼對照着看,這樣會更好一些。
再稍微講一下跳躍式移動或拉動控件的實現,FMoveStep指定跳躍的幅度,MoveX,MoveY:integer;用在移動點類和控件的鼠標事件中,累加鼠標移動的距離,當達到FMoveStep時,就移動控件,或改變控件的大小,然後將MoveX,MoveY變爲0,又繼續累加,如此循環
至於其他的就沒有什麼好說的了,各位還是看看源代碼吧,也並不是很難理解。代碼在第二部分給出。
控件移動類的實現之二 選擇自 linzhengqun 的 Blog
關鍵字 控件移動類的實現之二
出處
下面是TDragClass的源代碼,比如多,可以拷去機上試試,再慢慢看:
//------TDragClass------------------------
unit uDrag;
interface
uses Windows, Messages,Classes,SysUtils,Controls,Graphics,
uDragPoint,StdCtrls;
type
//控件的八個點,用於拉動大小
TPointRec=record
LeftTop:TDragPoint;
LeftBottom:TDragPoint;
RightTop:TDragPoint;
RightButton:TDragPoint;
LeftMid:TDragPoint;
TopMid:TDragPoint;
RightMid:TDragPoint;
ButtonMid:TDragPoint;
end;
TDragClass=class
private
FConList:TList; //保存控件的列表
FCurActiveCon:Integer; //當前活動控件
FPointRec:TPointRec; //當前控件的邊緣的八個小點
//跳躍式移動的成員
FisMoveStep:Boolean;
FMoveStep:integer;
MoveX,MoveY:integer;
//控件事件相關的成員
FConMouseDown:TMouseEvent;
FConMouseMove:TMouseMoveEvent;
FConMouseup:TMouseEvent;
isDown:Boolean;
prevP,nextP:TPoint;
protected
//-------對移動點的操作--
procedure CreateDragPoint(PointParent:TWinControl);
procedure SetPointPos(posRect:TRect);
procedure SetPointParent(PointParent:TWinControl);
procedure SetPointEvent;
procedure SetCurActiveCon(curCon:Pointer);
//----------------------
procedure MoveLeftTopPoint;
procedure AlignLeftTop;
procedure MoveLeftBottomPoint;
procedure AlignLeftBottom;
procedure MoveRightTopPoint;
procedure AlignRightTop;
procedure MoveRightBottomPoint;
procedure AlignRightBottom;
procedure MoveLeftMidPoint;
procedure AlignLeftMid;
procedure MoveTopMidPoint;
procedure AlignTopMid;
procedure MoveRightMidPoint;
procedure AlignRightMid;
procedure MoveBottomMidPoint;
procedure AlignBottomMid;
procedure reSizeCon;
//當前控件事件和移動點事件處理------------
procedure ConMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure ConMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure ConMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure PointMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure PointMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure PointMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure SetisMoveStep(value:Boolean);
procedure SetMoveStep(value:integer);
public
constructor create(PointParent:TWinControl);
destructor destroy; override;
function addControl(AddCon:Pointer):Boolean; //important
procedure SetPointVisible(Visibled:Boolean);
property isMoveStep:Boolean read FisMoveStep write SetisMoveStep;
property MoveStep:Integer read FMoveStep write SetMoveStep;
end;
implementation
{ TDragClass }
constructor TDragClass.create(PointParent:TWinControl);
begin
inherited Create;
FConList:=TList.Create;
FCurActiveCon:=-1;
isDown:=False;
FisMoveStep:=False;
FMoveStep:=5;
FConMouseDown:=ConMouseDown;
FConMouseMove:=ConMouseMove;
FConMouseup:=ConMouseUp;
CreateDragPoint(PointParent);
SetPointVisible(false);
SetPointEvent;
end;
destructor TDragClass.destroy;
begin
FreeAndNil(FConList);
FPointRec.LeftTop.Free;
FPointRec.LeftBottom.Free;
FPointRec.RightTop.Free;
FPointRec.RightButton.Free;
FPointRec.LeftMid.Free;
FPointRec.TopMid.Free;
FPointRec.RightMid.Free;
FPointRec.ButtonMid.Free;
inherited;
end;
//加一個控件進入拖拉類
function TDragClass.addControl(AddCon: Pointer): Boolean;
var TempCon:TControl; R:TRect;
i:integer;
begin
result:=True;
if TControl(AddCon).Parent=nil then
begin
result:=false;
exit;
end;
//如果該控件已經在列表中了,則加入失敗
for i:=0 to FConList.Count-1 do
if Integer(AddCon)=Integer(FConList.Items[i]) then
begin
result:=false;
exit;
end;
//將控件加入列表中,並指定當前的控件的索引
FConList.Add(AddCon);
FCurActiveCon:=FConList.Count-1;
TempCon:=TControl(AddCon);
TempCon.Cursor:=crSizeAll;
TempCon.Parent.DoubleBuffered:=True; //使用雙緩衝技術
//折中方案,指定控件鼠標事件
TButton(TempCon).OnMouseDown:=FconMouseDown;
TButton(TempCon).OnMouseMove:=FconMouseMove;
TButton(TempCon).OnMouseUp:=FconMouseUp;
//畫控件周圍的八個小點
R.Left:=TempCon.Left;
R.Top:=TempCon.Top;
R.Right:=TempCon.Left+TempCon.Width;
R.Bottom:=TempCon.Top+TempCon.Height;
SetPointParent(TempCon.Parent);
SetPointPos(R);
SetPointVisible(true);
end;
//設置八小點的可見性
procedure TDragClass.SetPointVisible(Visibled: Boolean);
begin
FPointRec.LeftTop.Visible:=Visibled;
FPointRec.LeftBottom.Visible:=Visibled;
FPointRec.RightTop.Visible:=Visibled;
FPointRec.RightButton.Visible:=Visibled;
FPointRec.LeftMid.Visible:=Visibled;
FPointRec.TopMid.Visible:=Visibled;
FPointRec.RightMid.Visible:=Visibled;
FPointRec.ButtonMid.Visible:=Visibled;
end;
//設置小點事件
procedure TDragClass.SetPointEvent;
begin
FPointRec.LeftTop.OnMouseDown:=PointMouseDown;
FPointRec.LeftTop.OnMouseMove:=PointMouseMove;
FPointRec.LeftTop.onMouseUp:=PointMouseUp;
FPointRec.LeftBottom.OnMouseDown:=PointMouseDown;
FPointRec.LeftBottom.OnMouseMove:=PointMouseMove;
FPointRec.LeftBottom.onMouseUp:=PointMouseUp;
FPointRec.RightTop.OnMouseDown:=PointMouseDown;
FPointRec.RightTop.OnMouseMove:=PointMouseMove;
FPointRec.RightTop.onMouseUp:=PointMouseUp;
FPointRec.RightButton.OnMouseDown:=PointMouseDown;
FPointRec.RightButton.OnMouseMove:=PointMouseMove;
FPointRec.RightButton.onMouseUp:=PointMouseUp;
FPointRec.LeftMid.OnMouseDown:=PointMouseDown;
FPointRec.LeftMid.OnMouseMove:=PointMouseMove;
FPointRec.LeftMid.onMouseUp:=PointMouseUp;
FPointRec.TopMid.OnMouseDown:=PointMouseDown;
FPointRec.TopMid.OnMouseMove:=PointMouseMove;
FPointRec.TopMid.onMouseUp:=PointMouseUp;
FPointRec.RightMid.OnMouseDown:=PointMouseDown;
FPointRec.RightMid.OnMouseMove:=PointMouseMove;
FPointRec.RightMid.onMouseUp:=PointMouseUp;
FPointRec.ButtonMid.OnMouseDown:=PointMouseDown;
FPointRec.ButtonMid.OnMouseMove:=PointMouseMove;
FPointRec.ButtonMid.onMouseUp:=PointMouseUp;
end;
//確定控件邊緣八個小點的位置
procedure TDragClass.SetPointPos(posRect: TRect);
begin
FPointRec.LeftTop.Left:=posRect.Left-6;
FPointRec.LeftTop.Top:=posRect.Top-6;
FPointRec.LeftBottom.Left:=PosRect.Left-6;
FPointRec.LeftBottom.Top:=PosRect.Bottom;
FPointRec.RightTop.Left:=posRect.Right;
FPointRec.RightTop.Top:=posRect.Top-6;
FPointRec.RightButton.Left:=PosRect.Right;
FPointRec.RightButton.Top:=PosRect.Bottom;
FPointRec.LeftMid.Left:=posRect.Left-6;
FPointRec.LeftMid.Top:=(posRect.Top+posRect.Bottom) div 2 - 3;
FPointRec.TopMid.Left:=(posRect.Left+posRect.Right) div 2 -3;
FPointRec.TopMid.Top:=PosRect.Top-6;
FPointRec.RightMid.Left:=posRect.Right;
FPointRec.RightMid.Top:=(posRect.Top+posRect.Bottom) div 2 - 3;
FPointRec.ButtonMid.Left:=(posRect.Left+posRect.Right) div 2 -3;
FPointRec.ButtonMid.Top:=PosRect.Bottom;
end;
//創建八個小點
procedure TDragClass.CreateDragPoint(PointParent:TWinControl);
begin
FPointRec.LeftTop:=TDragPoint.Create(nil);
FPointRec.LeftTop.Cursor:=crSizeNWSE;
FPointRec.LeftBottom:=TDragPoint.Create(nil);
FPointRec.LeftBottom.Cursor:=crSizeNESW;
FPointRec.RightTop:=TDragPoint.Create(nil);
FPointRec.RightTop.Cursor:=crSizeNESW;
FPointRec.RightButton:=TDragPoint.Create(nil);
FPointRec.RightButton.Cursor:=crSizeNWSE;
FPointRec.LeftMid:=TDragPoint.Create(nil);
FPointRec.LeftMid.Cursor:=crSizeWE;
FPointRec.TopMid:=TDragPoint.Create(nil);
FPointRec.TopMid.Cursor:=crSizeNS;
FPointRec.RightMid:=TDragPoint.Create(nil);
FPointRec.RightMid.Cursor:=crSizeWE;
FPointRec.ButtonMid:=TDragPoint.Create(nil);
FPointRec.ButtonMid.Cursor:=crSizeNS;
SetPointParent(PointParent);
end;
//------當前控件事件處理-------------------------
//處理點下的事件
procedure TDragClass.ConMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var TempCon:TControl; R:TRect;
begin
if Button=mbLeft then
begin
isDown:=True;
GetCursorPos(PrevP);
end;
TempCon:=TControl(Sender);
SetPointParent(TempCon.Parent);
R.Left:=TempCon.Left;
R.Top:=TempCon.Top;
R.Right:=TempCon.Left+TempCon.Width;
R.Bottom:=TempCon.Top+TempCon.Height;
MoveX:=0; MoveY:=0;
SetPointPos(R);
SetPointvisible(true);
SetCurActiveCon(TempCon);
end;
//處理當前控件移動的消息
procedure TDragClass.ConMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
var offsetX,offsetY:integer; con:TControl;
r:TRect;
begin
if isDown and (Shift=[ssLeft])then
begin
GetCursorPos(nextP);
offsetX:=NextP.X-PrevP.X;
offSetY:=NextP.Y-PrevP.Y;
Con:=TControl(Sender);
if not FisMoveStep then
begin
Con.Left:=Con.Left+offSetX;
Con.Top:=Con.Top+offSetY;
end
else begin
MoveX:=MoveX+offsetX;
MoveY:=MoveY+offsetY;
if Abs(MoveX)>=FMoveStep then
begin
Con.Left:=Con.Left+MoveX;
MoveX:=0;
end;
if Abs(MoveY)>FMoveStep then
begin
Con.Top:=Con.Top+MoveY;
MoveY:=0;
end;
end;
R.Left:=Con.Left;
R.Top:=Con.Top;
R.Right:=Con.Left+Con.Width;
R.Bottom:=Con.Top+Con.Height;
SetPointPos(R);
prevP:=nextP;
end;
end;
//處理當前控件鼠標彈起的消息
procedure TDragClass.ConMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
isDown:=False;
end;
//------------------------
//設置八個點的父子關係
procedure TDragClass.SetPointParent(PointParent: TWinControl);
begin
FPointRec.LeftTop.Parent:=PointParent;
FPointRec.LeftBottom.Parent:=PointParent;
FPointRec.RightTop.Parent:=PointParent;
FPointRec.RightButton.Parent:=PointParent;
FPointRec.LeftMid.Parent:=PointParent;
FPointRec.TopMid.Parent:=PointParent;
FPointRec.RightMid.Parent:=PointParent;
FPointRec.ButtonMid.Parent:=PointParent;
end;
//得到當前活動窗口
procedure TDragClass.SetCurActiveCon(curCon: Pointer);
var i:integer;
begin
for i:=0 to FConList.Count-1 do
if Integer(curCon)=Integer(FConList.Items[i]) then
begin
FCurActiveCon:=i;
break;
end;
end;
//----------------------------------
//八個小點的處理消息
procedure TDragClass.PointMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if Button= mbLeft then
begin
moveX:=0; moveY:=0;
if Sender=FPointRec.LeftTop then
begin
FpointRec.LeftTop.isDown:=True;
GetCursorPos(FPointRec.LeftTop.PrevP);
end
else if Sender=FPointRec.RightTop then
begin
FpointRec.RightTop.isDown:=True;
GetCursorPos(FPointRec.RightTop.PrevP);
end
else if Sender=FPointRec.LeftBottom then
begin
FpointRec.LeftBottom.isDown:=True;
GetCursorPos(FPointRec.LeftBottom.PrevP);
end
else if Sender=FPointRec.RightButton then
begin
FpointRec.RightButton.isDown:=True;
GetCursorPos(FPointRec.RightButton.PrevP);
end
else if Sender=FPointRec.LeftMid then
begin
FpointRec.LeftMid.isDown:=True;
GetCursorPos(FPointRec.LeftMid.PrevP);
end
else if Sender=FPointRec.TopMid then
begin
FpointRec.TopMid.isDown:=True;
GetCursorPos(FPointRec.TopMid.PrevP);
end
else if Sender=FPointRec.RightMid then
begin
FpointRec.RightMid.isDown:=True;
GetCursorPos(FPointRec.RightMid.PrevP);
end
else if Sender=FPointRec.ButtonMid then
begin
FpointRec.ButtonMid.isDown:=True;
GetCursorPos(FPointRec.ButtonMid.PrevP);
end;
end;
end;
procedure TDragClass.PointMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
if Shift=[ssLeft] then
begin
if FPointRec.LeftTop.isDown then
begin
MoveLeftTopPoint;
reSizeCon
end
else if FPointRec.LeftBottom.isDown then
begin
MoveLeftBottomPoint;
reSizeCon
end
else if FPointRec.RightTop.isDown then
begin
MoveRightTopPoint;
reSizeCon
end
else if FPointRec.RightButton.isDown then
begin
MoveRightBottomPoint;
reSizeCon
end
else if FPointRec.LeftMid.isDown then
begin
MoveLeftMidPoint;
reSizeCon
end
else if FPointRec.TopMid.isDown then
begin
MoveTopMidPoint;
reSizeCon
end
else if FPointRec.RightMid.isDown then
begin
MoveRightMidPoint;
reSizeCon
end
else if FPointRec.ButtonMid.isDown then
begin
MoveBottomMidPoint;
reSizeCon
end
end;
end;
procedure TDragClass.PointMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if Button= mbLeft then
begin
if (FpointRec.LeftTop.isDown) and
(Sender=FpointRec.LeftTop) then
FpointRec.LeftTop.isDown:=False
else if (FpointRec.LeftBottom.isDown) and
(Sender=FpointRec.LeftBottom) then
FpointRec.LeftBottom.isDown:=False
else if (FpointRec.RightTop.isDown) and
(Sender=FpointRec.RightTop) then
FpointRec.RightTop.isDown:=False
else if (FpointRec.RightButton.isDown) and
(Sender=FpointRec.RightButton) then
FpointRec.RightButton.isDown:=False
else if (FpointRec.LeftMid.isDown) and
(Sender=FpointRec.LeftMid) then
FpointRec.LeftMid.isDown:=False
else if (FpointRec.TopMid.isDown) and
(Sender=FpointRec.TopMid) then
FpointRec.TopMid.isDown:=False
else if (FpointRec.RightMid.isDown) and
(Sender=FpointRec.RightMid) then
FpointRec.RightMid.isDown:=False
else if (FpointRec.ButtonMid.isDown) and
(Sender=FpointRec.ButtonMid) then
FpointRec.ButtonMid.isDown:=False;
end;
end;
//左頂點的移動
procedure TDragClass.MoveLeftTopPoint;
var offsetX,offsetY:Integer;
begin
GetCursorPos(FPointRec.LeftTop.NextP);
offsetX:=FPointRec.LeftTop.NextP.X-FPointRec.LeftTop.PrevP.X;
offSetY:=FPointRec.LeftTop.NextP.Y-FPointRec.LeftTop.PrevP.Y;
if not FisMoveStep then
begin
FPointRec.LeftTop.Left:=FPointRec.LeftTop.Left+offsetX;
FPointRec.LeftTop.Top:=FPointRec.LeftTop.Top+offsetY;
end
else begin
MoveX:=MoveX+offsetX;
MoveY:=MoveY+offsetY;
if Abs(moveX)>=FMoveStep then
begin
FPointRec.LeftTop.Left:=FPointRec.LeftTop.Left+moveX;
moveX:=0;
end;
if Abs(moveY)>=FMoveStep then
begin
FPointRec.LeftTop.Top:=FPointRec.LeftTop.Top+moveY;
moveY:=0;
end;
end;
FPointRec.LeftTop.PrevP:=FPointRec.LeftTop.NextP;
AlignLeftTop;
end;
//其他點對齊左右點
procedure TDragClass.AlignLeftTop;
begin
FPointRec.LeftBottom.Left:=FPointRec.LeftTop.Left;
FPointRec.RightTop.Top:=FPointRec.LeftTop.Top;
FPointRec.LeftMid.Left:=FPointRec.LeftTop.Left;
FPointRec.LeftMid.Top:=
(FPointRec.LeftBottom.Top+FPointRec.LeftTop.Top) div 2;
FPointRec.TopMid.Top:=FPointRec.LeftTop.Top;
FPointRec.TopMid.Left:=
(FPointRec.RightTop.Left+FPointRec.LeftTop.Left) div 2;
FPointRec.RightMid.Top:=
(FPointRec.RightTop.Top+FPointRec.RightButton.Top) div 2;
FPointRec.ButtonMid.Left:=
(FPointRec.LeftBottom.Left+FPointRec.RightButton.Left) div 2;
end;
//對齊點
procedure TDragClass.AlignLeftBottom;
begin
FPointRec.LeftTop.Left:=FPointRec.LeftBottom.Left;
FPointRec.RightButton.Top:=FPointRec.LeftBottom.Top;
FPointRec.LeftMid.Left:=FPointRec.LeftTop.Left;
FPointRec.LeftMid.Top:=
(FPointRec.LeftBottom.Top+FPointRec.LeftTop.Top) div 2;
FPointRec.TopMid.Top:=FPointRec.LeftTop.Top;
FPointRec.TopMid.Left:=
(FPointRec.RightTop.Left+FPointRec.LeftTop.Left) div 2;
FPointRec.RightMid.Top:=
(FPointRec.RightTop.Top+FPointRec.RightButton.Top) div 2;
FPointRec.ButtonMid.Top:=FPointrec.LeftBottom.Top;
FPointRec.ButtonMid.Left:=
(FPointRec.LeftBottom.Left+FPointRec.RightButton.Left) div 2;
end;
//移動左底點
procedure TDragClass.MoveLeftBottomPoint;
var offsetX,offsetY:Integer;
begin
GetCursorPos(FPointRec.LeftBottom.NextP);
offsetX:=FPointRec.LeftBottom.NextP.X-FPointRec.LeftBottom.PrevP.X;
offSetY:=FPointRec.LeftBottom.NextP.Y-FPointRec.LeftBottom.PrevP.Y;
if not FisMoveStep then
begin
FPointRec.LeftBottom.Left:=FPointRec.LeftBottom.Left+offsetX;
FPointRec.LeftBottom.Top:=FPointRec.LeftBottom.Top+offsetY;
end
else begin
MoveX:=MoveX+offsetX;
MoveY:=MoveY+offsetY;
if Abs(moveX)>=FMoveStep then
begin
FPointRec.LeftBottom.Left:=FPointRec.LeftBottom.Left+moveX;
moveX:=0;
end;
if Abs(moveY)>=FMoveStep then
begin
FPointRec.LeftBottom.Top:=FPointRec.LeftBottom.Top+moveY;
movey:=0;
end;
end;
FPointRec.LeftBottom.PrevP:=FPointRec.LeftBottom.NextP;
AlignLeftBottom;
end;
//對齊點
procedure TDragClass.AlignRightTop;
begin
FPointRec.LeftTop.Top:=FPointRec.RightTop.top;
FPointRec.RightButton.Left:=FPointRec.RightTop.Left;
FPointRec.LeftMid.Left:=FPointRec.LeftTop.Left;
FPointRec.LeftMid.Top:=
(FPointRec.LeftBottom.Top+FPointRec.LeftTop.Top) div 2;
FPointRec.TopMid.Top:=FPointRec.LeftTop.Top;
FPointRec.TopMid.Left:=
(FPointRec.RightTop.Left+FPointRec.LeftTop.Left) div 2;
FPointRec.RightMid.Left:=FPointRec.RightTop.Left;
FPointRec.RightMid.Top:=
(FPointRec.RightTop.Top+FPointRec.RightButton.Top) div 2;
FPointRec.ButtonMid.Top:=FPointrec.LeftBottom.Top;
FPointRec.ButtonMid.Left:=
(FPointRec.LeftBottom.Left+FPointRec.RightButton.Left) div 2;
end;
//移動右上點
procedure TDragClass.MoveRightTopPoint;
var offsetX,offsetY:Integer;
begin
GetCursorPos(FPointRec.RightTop.NextP);
offsetX:=FPointRec.RightTop.NextP.X-FPointRec.RightTop.PrevP.X;
offSetY:=FPointRec.RightTop.NextP.Y-FPointRec.RightTop.PrevP.Y;
if not FisMoveStep then
begin
FPointRec.RightTop.Left:=FPointRec.RightTop.Left+offsetX;
FPointRec.RightTop.Top:=FPointRec.RightTop.Top+offsetY;
end
else begin
MoveX:=MoveX+offsetX;
MoveY:=MoveY+offsetY;
if Abs(moveX)>=FMoveStep then
begin
FPointRec.RightTop.Left:=FPointRec.RightTop.Left+moveX;
moveX:=0;
end;
if Abs(moveY)>=FMoveStep then
begin
FPointRec.RightTop.Top:=FPointRec.RightTop.Top+moveY;
moveY:=0;
end;
end;
FPointRec.RightTop.PrevP:=FPointRec.RightTop.NextP;
AlignRightTop;
end;
//對齊點
procedure TDragClass.AlignRightBottom;
begin
FPointRec.LeftBottom.Top:=FPointRec.RightButton.top;
FPointRec.RightTop.Left:=FPointRec.RightButton.Left;
FPointRec.LeftMid.Left:=FPointRec.LeftTop.Left;
FPointRec.LeftMid.Top:=
(FPointRec.LeftBottom.Top+FPointRec.LeftTop.Top) div 2;
FPointRec.TopMid.Top:=FPointRec.LeftTop.Top;
FPointRec.TopMid.Left:=
(FPointRec.RightTop.Left+FPointRec.LeftTop.Left) div 2;
FPointRec.RightMid.Left:=FPointRec.RightTop.Left;
FPointRec.RightMid.Top:=
(FPointRec.RightTop.Top+FPointRec.RightButton.Top) div 2;
FPointRec.ButtonMid.Top:=FPointrec.LeftBottom.Top;
FPointRec.ButtonMid.Left:=
(FPointRec.LeftBottom.Left+FPointRec.RightButton.Left) div 2;
end;
//移動右底點
procedure TDragClass.MoveRightBottomPoint;
var offsetX,offsetY:Integer;
begin
GetCursorPos(FPointRec.RightButton.NextP);
offsetX:=FPointRec.RightButton.NextP.X-FPointRec.RightButton.PrevP.X;
offSetY:=FPointRec.RightButton.NextP.Y-FPointRec.RightButton.PrevP.Y;
if not FisMoveStep then
begin
FPointRec.RightButton.Left:=FPointRec.RightButton.Left+offsetX;
FPointRec.RightButton.Top:=FPointRec.RightButton.Top+offsetY;
end
else begin
MoveX:=MoveX+offsetX;
MoveY:=MoveY+offsetY;
if Abs(moveX)>=FMoveStep then
begin
FPointRec.RightButton.Left:=FPointRec.RightButton.Left+moveX;
moveX:=0;
end;
if Abs(moveY)>=FMoveStep then
begin
FPointRec.RightButton.Top:=FPointRec.RightButton.Top+moveY;
moveY:=0;
end;
end;
FPointRec.RightButton.PrevP:=FPointRec.RightButton.NextP;
AlignRightBottom;
end;
//對齊點
procedure TDragClass.AlignLeftMid;
begin
FPointRec.LeftTop.Left:=FPointRec.LeftMid.Left;
FPointRec.LeftBottom.Left:=FPointRec.LeftMid.Left;
FPointRec.TopMid.Top:=FPointRec.LeftTop.Top;
FPointRec.TopMid.Left:=
(FPointRec.RightTop.Left+FPointRec.LeftTop.Left) div 2;
FPointRec.ButtonMid.Top:=FPointrec.LeftBottom.Top;
FPointRec.ButtonMid.Left:=
(FPointRec.LeftBottom.Left+FPointRec.RightButton.Left) div 2;
end;
//左中點
procedure TDragClass.MoveLeftMidPoint;
var offsetX:Integer;
begin
GetCursorPos(FPointRec.LeftMid.NextP);
offsetX:=FPointRec.LeftMid.NextP.X-FPointRec.LeftMid.PrevP.X;
if not FisMoveStep then
begin
FPointRec.LeftMid.Left:=FPointRec.LeftMid.Left+offsetX;
end
else begin
MoveX:=MoveX+offsetX;
if Abs(moveX)>=FMoveStep then
begin
FPointRec.LeftMid.Left:=FPointRec.LeftMid.Left+moveX;
moveX:=0;
end;
end;
FPointRec.LeftMid.PrevP:=FPointRec.LeftMid.NextP;
AlignLeftMid;
end;
//對齊點
procedure TDragClass.AlignTopMid;
begin
FPointRec.LeftTop.Top:=FPointRec.TopMid.Top;
FPointRec.RightTop.Top:=FPointRec.TopMid.Top;
FPointRec.TopMid.Top:=FPointRec.LeftTop.Top;
FPointRec.LeftMid.Left:=FPointRec.LeftTop.Left;
FPointRec.LeftMid.Top:=
(FPointRec.LeftBottom.Top+FPointRec.LeftTop.Top) div 2;
FPointRec.RightMid.Left:=FPointRec.RightTop.Left;
FPointRec.RightMid.Top:=
(FPointRec.RightTop.Top+FPointRec.RightButton.Top) div 2;
end;
//頂中點
procedure TDragClass.MoveTopMidPoint;
var offsetY:Integer;
begin
GetCursorPos(FPointRec.TopMid.NextP);
offSetY:=FPointRec.TopMid.NextP.Y-FPointRec.TopMid.PrevP.Y;
if not FisMoveStep then
begin
FPointRec.TopMid.Top:=FPointRec.TopMid.Top+offsetY;
end
else begin
MoveY:=MoveY+offsetY;
if Abs(moveY)>=FMoveStep then
begin
FPointRec.TopMid.Top:=FPointRec.TopMid.Top+moveY;
moveY:=0;
end;
end;
FPointRec.TopMid.PrevP:=FPointRec.TopMid.NextP;
AlignTopMid;
end;
//對齊點
procedure TDragClass.AlignRightMid;
begin
FPointRec.RightTop.Left:=FPointRec.RightMid.Left;
FPointRec.RightButton.Left:=FPointRec.RightMid.Left;
FPointRec.TopMid.Top:=FPointRec.LeftTop.Top;
FPointRec.TopMid.Left:=
(FPointRec.RightTop.Left+FPointRec.LeftTop.Left) div 2;
FPointRec.ButtonMid.Top:=FPointrec.LeftBottom.Top;
FPointRec.ButtonMid.Left:=
(FPointRec.LeftBottom.Left+FPointRec.RightButton.Left) div 2;
end;
//右中點
procedure TDragClass.MoveRightMidPoint;
var offsetX:Integer;
begin
GetCursorPos(FPointRec.RightMid.NextP);
offsetX:=FPointRec.RightMid.NextP.X-FPointRec.RightMid.PrevP.X;
if not FisMoveStep then
begin
FPointRec.RightMid.Left:=FPointRec.RightMid.Left+offsetX;
end
else begin
MoveX:=MoveX+offsetX;
if Abs(moveX)>=FMoveStep then
begin
FPointRec.RightMid.Left:=FPointRec.RightMid.Left+moveX;
moveX:=0;
end;
end;
FPointRec.RightMid.PrevP:=FPointRec.RightMid.NextP;
AlignRightMid;
end;
//對齊點
procedure TDragClass.AlignBottomMid;
begin
FPointRec.LeftBottom.Top:=FPointRec.ButtonMid.Top;
FPointRec.RightButton.Top:=FPointrec.ButtonMid.Top;
FPointRec.LeftMid.Left:=FPointRec.LeftTop.Left;
FPointRec.LeftMid.Top:=
(FPointRec.LeftBottom.Top+FPointRec.LeftTop.Top) div 2;
FPointRec.RightMid.Left:=FPointRec.RightTop.Left;
FPointRec.RightMid.Top:=
(FPointRec.RightTop.Top+FPointRec.RightButton.Top) div 2;
end;
//底中點
procedure TDragClass.MoveBottomMidPoint;
var offsetY:Integer;
begin
GetCursorPos(FPointRec.ButtonMid.NextP);
offSetY:=FPointRec.ButtonMid.NextP.Y-FPointRec.ButtonMid.PrevP.Y;
if not FisMoveStep then
begin
FPointRec.ButtonMid.Top:=FPointRec.ButtonMid.Top+offsetY;
end
else begin
MoveY:=MoveY+offsetY;
if Abs(moveY)>=FMoveStep then
begin
FPointRec.ButtonMid.Top:=FPointRec.ButtonMid.Top+moveY;
moveY:=0;
end;
end;
FPointRec.ButtonMid.PrevP:=FPointRec.ButtonMid.NextP;
AlignBottomMid;
end;
//重定位控件的盡寸
procedure TDragClass.reSizeCon;
var Con:TControl;
begin
Con:=TControl(FConList.Items[FCurActiveCon]);
Con.Left:=FPointRec.LeftTop.Left+FPointRec.LeftTop.Width;
Con.Top:=FPointRec.LeftTop.Top+FPointRec.LeftTop.Height;
Con.Width:=FPointRec.RightTop.Left-Con.Left;
Con.Height:=FPointRec.LeftBottom.Top-Con.Top;
end;
//-----------------------------------------------
//設置控件移動時是否用跳躍式的移動
procedure TDragClass.SetisMoveStep(value: Boolean);
begin
if FisMoveStep<>value then
FisMoveStep:=Value;
end;
//設置控件移動跳躍的距離
procedure TDragClass.SetMoveStep(value: integer);
begin
if Value<5 then
FMoveStep:=5
else if Value>20 then
FMoveStep:=20
else
FMoveStep:=Value;
end;
end.
到第三部分,用一個例子來說明這個類的用法
我們用一個例子來演示這個類的用法,建一個工程,將TDragClass的單元加入主窗體單元中,代碼如下:
unit Main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, StdCtrls, ExtCtrls, Buttons,uDrag,uDragPoint, jpeg;
type
TForm1 = class(TForm)
Bevel1: TBevel;
Button3: TButton; //指定用何種方式移動和拉動
Edit2: TEdit;//用於設定跳躍式移動的幅度
Button4: TButton;//確定Edit2中的內容
Button1: TButton;//點擊該按鈕,加入下面的控件,實現控件移動
Panel1: TPanel;
Shape1: TShape;
Image1: TImage;
Button2: TButton;
Edit1: TEdit;
StaticText1: TStaticText;
Shape2: TShape;
BitBtn1: TBitBtn;
BitBtn2: TBitBtn;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure FormClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
MyDrag:TDragClass;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
myDrag.addControl(Edit1);
myDrag.addControl(Button2);
myDrag.addControl(Shape1);
myDrag.addControl(Image1);
myDrag.addControl(Panel1);
myDrag.addControl(BitBtn1);
myDrag.addControl(shape2);
myDrag.addControl(BitBtn2);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
myDrag:=TDragClass.create(self);
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if Assigned(myDrag) then
MyDrag.Free;
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
myDrag.isMoveStep:=not myDrag.isMoveStep;
if myDrag.isMoveStep then
Button3.Caption:='連接式移動'
else
Button3.Caption:='跳躍式移動';
end;
procedure TForm1.Button4Click(Sender: TObject);
var value:integer;
begin
if TryStrtoInt(Edit2.Text,value) then
myDrag.MoveStep:=value;
end;
procedure TForm1.FormClick(Sender: TObject);
begin
myDrag.SetPointVisible(false);
end;
end.
運行程序,點擊Button1按鈕,看看如何,下面的控件是不是都可以移動了呢,再點擊Button3,控件的移動是不是變得不連續了呢,再輸入Edit2的值,然後點確定,控件移動的不連續性是不是變化了呢。
至此這個控件移動類講解完畢,但還有很多改善的地方,有興趣自己改吧。還是那句話,希望對你有用。
(出處:www.delphibbs.com)