lincanwen(密码错误) 的方法是浮动窗口,我是想要资源管理器那样。 geyobing(银翼天使) 的方法可能比较耗内存:“窗体创建的时候,一大堆的控件被创建,占用内存”。附带问一句,我的三个panel的align应该设,splitter是不是要2个 | A | B | ________|_________ C
硬的办法如下:使用类型参考 type TFormClass = class of TForm;建两个数组: 类成员 MyForm: array[1..n] of TForm; MyFormClass: array[1..n] of TFormClasstreeviewclick事件 MyForm[FormCount] := TFormI.create(self); //单击第i个item,生成对应FormI,并保存之。因为不知道用户会单击哪个item,只能保存到类型为基类TForm的数组中 MyFomClass[FormCount] :=TFormI FormCount := FormCount + 1;close事件 for i:= 1 to FormCount if ((MyForm[i] as TMyFormClass[i]).bDataIsChanged) //如果第i个form中的数据发生变化,则保存数据,此时需要访问子类对象定义的成员bDataIsChanged,但MyForm[i]是基类对象,不能访问子类对象的成员bDataIsChanged,因此需要类型转换,从而又需要知道MyForm[i]所保存form的类型,也就是说,判断出它所保存的,到底是TFormN中的哪一个。
1. 这样的话,formi不能用MDIForm了。(试过不行) 2. mainform也许可以用MDIForm。(我没试过)3. 整理一下本帖中的绝大部分问题(也许还有没理解透的)的思路如下: A). mainfrom对formL,formI,formN的调用,采用我上贴的解决方法。 即:用CurrentForm来记住当前窗体 B). formI对formI0, formI1, ... ,formIn的调用,还是采用前述用Panel作parent的想法。 C). 平铺的控制只好自己写罗 简单的两个水平、垂直我已经测试过了 procedure TForm2.Button1Click(Sender: TObject); var i:integer; begin for i:=0 to panel2.ControlCount-1 do with Panel2.Controls[i] do Align:=alNone; for i:=0 to panel2.ControlCount-1 do with Panel2.Controls[i] do begin Width:=Panel2.ClientWidth div panel2.ControlCount; //Width:=Panel2.ClientWidth; Height:=Panel2.ClientHeight; //Height:=Panel2.ClientHeight div panel2.ControlCount; Align:=alLeft; //alTop end; end;
我把问题整理了一下。 非客户区(菜单和工具栏),记作mainframe / | \ form1 formi formN / | \ formi1 formij formiM如上图所示,程序中的form分为两级。 第一级的N个form共用同一个非客户区(菜单和工具栏),用户登录后将出现form1,日常运行时则通过单击菜单进行N个form之间的切换,任何时刻有且仅有一个第一级form。 在第一级的form中,有的只有它自己一个窗口,有的则还有自己的子窗口。 | A | B | ________|_________ C如上图所示,A、B、C共同构成有子窗口的第一级formi的客户区,它们之间的相对大小可由用户动态调整。 formi的子窗口formij只能局限于B区,其数目是由用户实际的操作(双击A区中treeview的item,此时增加一个formij;和主动单击formij的关闭按钮,此时相应的formij被关闭)所决定的,没有事先的限制(可以为0到无穷)。 每个formij在启动时读数据库,在关闭时写数据库,在formi因为用户单击了其它菜单项而被替换和因为主程序被关闭而被关闭时也要写数据库。希望能实现批量写数据库,例如不是在formij关闭时写数据库,而是在formi被关闭时写数据库,这样速度可能会快一些。 对于B区中的formij,要求在B的范围内支持层叠和平铺操作(不能超出B的边界),并且希望在B区能有一个独立的工具栏,即如右下图所示。 mainframe's toolbar mainframe's toolbar | B's toolbar | A | B A | B _____|_______ _________|________请各位朋友多多指教,本人不甚感激。
To gub(gub) 主要的不便是:没有OnCreate/OnClose/OnShow(有OnResize)事件。贴一个小元件做补丁:unit FrameMove;interfaceuses SysUtils, Classes, Controls, Forms, Dialogs;type TFrameQueryEvent = procedure(Sender: TObject; var Enable: Boolean) of Object; TFrameMove = class(TComponent) private { Private declarations } FParentLeft: Integer; FParentTop: Integer; FOnInsertQuery: TFrameQueryEvent; FOnRemoveQuery: TFrameQueryEvent; FOnInsert: TNotifyEvent; FOnRemove: TNotifyEvent; function GetFrame: TFrame; function GetIsInsert: Boolean; procedure SetParentLeft(const Value: Integer); procedure SetParentTop(const Value: Integer); protected { Protected declarations } function CanInsert: Boolean; virtual; function CanRemove: Boolean; virtual; public { Public declarations } constructor Create(AOwner: TComponent); override; function InsertFrame(FrameParent: TWinControl): Boolean; function RemoveFrame: Boolean; property Frame: TFrame read GetFrame; property IsInsert: Boolean read GetIsInsert; published { Published declarations } property ParentLeft: Integer read FParentLeft write SetParentLeft default 0; property ParentTop: Integer read FParentTop write SetParentTop default 0; property OnInsertQuery: TFrameQueryEvent read FOnInsertQuery write FOnInsertQuery; property OnRemoveQuery: TFrameQueryEvent read FOnRemoveQuery write FOnRemoveQuery; property OnInsert: TNotifyEvent read FOnInsert write FOnInsert; property OnRemove: TNotifyEvent read FOnRemove write FOnRemove; end;procedure Register;implementationprocedure Register; begin RegisterComponents('User', [TFrameMove]); end;{ TFrameMove }function TFrameMove.CanInsert: Boolean; begin Result := not IsInsert; if Result and Assigned(OnInsertQuery) then OnInsertQuery(Self, Result); end;function TFrameMove.CanRemove: Boolean; begin Result := True; if Assigned(OnRemoveQuery) then OnRemoveQuery(Self, Result); end;constructor TFrameMove.Create(AOwner: TComponent); begin if AOwner is TFrame then inherited Create(AOwner) else ShowMessage('TFrameMove必须放在TFrame元件上.'); end;function TFrameMove.GetFrame: TFrame; begin Result := TFrame(Owner); end;function TFrameMove.GetIsInsert: Boolean; begin Result := Frame.HasParent; end;function TFrameMove.InsertFrame(FrameParent: TWinControl): Boolean; begin Result := CanInsert and Assigned(FrameParent); if Result then begin Frame.Parent := FrameParent; if ParentLeft <> 0 then Frame.Left := ParentLeft; if ParentTop <> 0 then Frame.Top := ParentTop; if Assigned(OnInsert) then OnInsert(Self); end; end;function TFrameMove.RemoveFrame: Boolean; begin if IsInsert then begin Result := CanRemove; if Result then begin Frame.Parent := nil; if Assigned(OnRemove) then OnRemove(Self); end; end else Result := True; end;procedure TFrameMove.SetParentLeft(const Value: Integer); begin if FParentLeft <> Value then begin FParentLeft := Value; if IsInsert then Frame.Left := Value; end; end;procedure TFrameMove.SetParentTop(const Value: Integer); begin if FParentTop <> Value then begin FParentTop := Value; if IsInsert then Frame.Top := Value; end; end;end.
To: maozefa(之源)兄: 这个思路很好,佩服的很。学习中。 OnInsert/OnRemove事件应该是弥补OnCreate/OnClose事件的吧。 可是测试时,没有触发这两个事件啊。是不是还有什么bug。
每次treeview被click时,动态创建右上的form,置form的parent为panel再显示。
记住要关闭上一个form.
Form2.CreateParented(Panel1.Handle);
这里用PageControl不是很好。(我最喜欢用PageControl了,因为我喜欢做wizard)。
窗体创建的时候,一大堆的控件被创建,占用内存等等to 楼主:
from1:=Tform1.create(self);
form1.parent:=Panle1;
form1.align:=alClient;
form1.show;
另外,要判断panel1中是不是有窗体,有就要free.
方法二、使用组件NoteBook(Win3.1)
建立2个form,分别为form1,form2,
在form1上增加:button1,panel1,panel的docksite属性设置为true;form2的dragking属性设置为dkDock;在form1的button2的click事件中:
Form2.Show;
Form2.ManualDock(Panel1, nil);
form2.FormStyle:=fsStayOnTop;
看看做了这个列子可不可以帮你。
建立2个form,分别为form1,form2,
在form1上增加:button1,panel1,panel的docksite属性设置为true;form2的dragking属性设置为dkDock;在form1的button1的click事件中:
Form2.Show;
Form2.ManualDock(Panel1, nil);
form2.FormStyle:=fsStayOnTop;
看看做了这个列子可不可以帮你。
我下了一个局域网浏览器,感觉太复杂了,而且和我的要求也不太一样。
麻烦各位出出主意,多谢!
geyobing(银翼天使) 的方法可能比较耗内存:“窗体创建的时候,一大堆的控件被创建,占用内存”。附带问一句,我的三个panel的align应该设,splitter是不是要2个 |
A | B
|
________|_________ C
根据需要动态生成form,并把生成的form的parent设为panel,
其实最好应该使用Tframe,比较方便。
你可以设置 动态form的borderstyle 为bsNone啊。
绝对没问题的。我是从DevExpress的一些例子的源码里学到的。
不过还有两个相关问题。
我改变了主意,希望在一个panel中出现多个窗口(以前是只有一个,这个问题已经解决)
1. 怎样使一个panel中的多个窗口水平平铺、垂直平铺?
2. 怎样释放一个form,是用free还是用destroy?用父类变量,如TForm去释放子类变量,如TFormN会有问题吗,要不要声明为virtual。
新建的窗口的标题栏是灰的,上面的edit控件不能接受焦点,上面的button倒是可以接受click事件。
对我来说,标题栏是灰的倒无所谓,但edit肯定要能够编辑啊。
如果borderstyle为默认的bsSizable,要先按右键,此时edit中所有文本将被选中,再点左键,就可以编辑了;
如果borderstyle为bsNone,则和通常一样,直接点左键就可以了。我希望能在同一个panel中显示多个窗口,能对这多个窗口设置平铺方式,并且能够直接点左键就可以编辑edit。另外,动态生成TFormN再赋给TForm将不能访问TFormN的新增成员(父类对象不能访问子类对象的成员)。怎样获得TForm所指对象的类型(是指向哪个TFormi),再进行类型转换,以访问子类对象的成员。
呵呵,有些我就没实践过了,只好先出点子。
1. 引申啊
建一个MDIForm,它的parent为panel1,borderstyle为bsNone,align为alClient;
其他的form都是MDIForm的子form啦;
这样,平铺什么的不是很方便吗?
2. free会去调Detroy的;所以我们free就可以了
“另外,动态生成TFormN再赋给TForm将不能访问TFormN的新增成员(父类对象不能访问子类对象的成员)。怎样获得TForm所指对象的类型(是指向哪个TFormi),再进行类型转换,以访问子类对象的成员。”
不太明白。
烦请说的详细点。
如果不急,可以给你做个例子。
MyForm: array[1..n] of TForm;treeviewclick事件
MyForm[FormCount] = TFormI.create(self); //单击第i个item,生成对应FormI,并保存之。因为不知道用户会单击哪个item,只能保存到类型为基类TForm的数组中
FormCount := FormCount + 1;close事件
for i:= 1 to FormCount
if (MyForm[i].bDataIsChanged) //如果第i个form中的数据发生变化,则保存数据,此时需要访问子类对象定义的成员bDataIsChanged,但MyForm[i]是基类对象,不能访问子类对象的成员bDataIsChanged,因此需要类型转换,从而又需要知道MyForm[i]所保存form的类型,也就是说,判断出它所保存的,到底是TFormN中的哪一个。
我用树来表示类别,类别是固定的,但每一类可以有多个对象,而对象的数目是不定的,可以为0到无穷。
如果对象也是固定的,就可以为每个对象都声明一个form变量,单击哪个对象(item)就使用相应的form变量,这样就把通过基类对象访问子类对象成员的问题给绕过去了。
可是一连回复了三次。又没有马甲,不能回复了。
其实有个简单的办法。D7下已经测试成功。如下:主form设为MDIForm,其他form设为MDIChild
不用建panel1了。
直接放C区的panel,alBottom
再放splitter1,alBottom
再放A区的TreeView,alLeft
再放splitter2,alLeft.
然后点击TreeView的节点时,创建各MDIChild Form就是了。
当然Casacade,Tile都有了。
硬的解决方法是有的,不过我觉得比较麻烦。为什么不变一下思路?
子form的保存 由 子form自己在close的时候进行,
这样主form只close各子form就行了。
这样也符合面向对象的思想啊。这样做有什么不便,请再说明。
type
TFormClass = class of TForm;建两个数组:
类成员
MyForm: array[1..n] of TForm;
MyFormClass: array[1..n] of TFormClasstreeviewclick事件
MyForm[FormCount] := TFormI.create(self); //单击第i个item,生成对应FormI,并保存之。因为不知道用户会单击哪个item,只能保存到类型为基类TForm的数组中
MyFomClass[FormCount] :=TFormI
FormCount := FormCount + 1;close事件
for i:= 1 to FormCount
if ((MyForm[i] as TMyFormClass[i]).bDataIsChanged) //如果第i个form中的数据发生变化,则保存数据,此时需要访问子类对象定义的成员bDataIsChanged,但MyForm[i]是基类对象,不能访问子类对象的成员bDataIsChanged,因此需要类型转换,从而又需要知道MyForm[i]所保存form的类型,也就是说,判断出它所保存的,到底是TFormN中的哪一个。
1 在主form被关闭时如何通知子form执行close操作
是否是主动调用子form的close。如果是的话,用下面的语句是否可行,在子form的close中写数据库是否来得及(因为窗口马上就要关闭了)。
for i:= 1 to FormCount
MyForm[i].close; //MyForm是TForm型变量,它保存了TFormN型对象,但它不知道所保存的是TFormN中的哪一种
2 子form如何主动通知主form它已被用户关闭
因为用户完全可以主动关闭某一个子form我用delphi 6实现了在delphi 7下使用MDIForm和MDIChild的方法,是可行的,但MDIChild最大化后的效果不太好:
3 整个程序的标题栏
把MDIChild最大化后,整个程序的标题栏出现了 [Form2] 的字样,这对通常的MDI程序来说是合理的,但我不希望出现这些字样,如何重载它的最大化事件,使得不出现这些字样。
4 MDIChild的标题栏消失了
把MDIChild最大化后,MDIChild的标题栏消失了,而通常的MDI程序是有两个标题栏的,一个是整个程序的,一个是MDIChild自己的,delphi的MDI demo可以实现这样的效果,但我没看出来是哪个地方使它具有这样的效果。当然,这个问题不是非常重要,不能解决也问题不大。5 对于上面的这种方法,能否为B区设一个单独的工具栏,我想把诸如水平平铺、垂直平铺之类的按钮放在这个工具栏上。当然,这个问题也不是非常重要。6 如何把客户区中的当前form用另一个form给替换掉
因为不同的菜单项对应不同的form,单击菜单的某一项,当前form就消失,该菜单项相应的form就create和show。我想了一个最笨的方法,就是把这个菜单放到每个form上去,用户以为是替换的客户区,事实上却是替换了整个form。但这样做代码的冗余就大为增加了,而且也很麻烦。不知有什么好的方法。
for i:= 1 to FormCount
if MyForm[i]<> nil then //MyForm[i]没有被释放
MyForm[i].close;
在OnClose里面执行操作是没问题的。因为,它实际发生在form真正关闭前。
这里可能会有问题,因为主form不知该调用哪一个Close.因为它不知道MyForm[i]是什么
类的。也许它会调用TForm.close。所以,还是使用类型参考吧。(见上贴)2. 子form关闭(OnClose的最后)时,加一句:
action:=caFree;
formI:=nil;//表示Formi此时已被释放3. 实在不行,在每个子form的OnMaximize里面写上:
caption:='';
再在OnRestore/OnMinimize里把caption改回来。4. 试试在OnMaximize写个控制,不让MDIChild最大化。
6. 如果同时不让用户看到多个form,为什么不showmodal呢?
当然不showmodal也是可以实现的。
能不能定义一个Tform变量,记住当前那个form呢?这几天比较忙,可能没时间测试了。
仓促之间的一些想法,如果误导了您,请见谅。
2. MDI的mainform应该能够知道它的某个childform被用户关闭了吧。如果使用formI:=nil;就要求查找主form中的数组,因为子form并不知道它被保存在数组的第几个元素中。除非我们为每个item都在数组中保留固定的位置。
3、4 实在没办法,就不允许用户最大化了
5
6 如果showmodal,用户虽然不能切换到主界面,但他是可以看见主界面的,除非我们能够保证其它所有界面都比主界面大,而且用户不能移动当前的界面。至于用TForm变量,我不知道该怎么做。这几天的讨论使我受益匪浅,作为唯一的表示谢意的方法,我一定会另外开帖,恭敬给分,以此来表达我心中的谢意!
| A | B
A | B _____|_______
form的close我们并没有重载,应该可以找到。
我的意思是主form能否找到某个子form的OnClose事件代码。因为他不知道该子form的类。2. 这种写法并不麻烦,多加一行if语句而已;效率影响也不大;
而主form中的数组中存放的只是FormI的引用(指针而已),也不怎么耗内存。6. MDIForm有个属性:ActiveMDIChild
每次打开下一个form的时候,
if self.ActiveMDIChild <> nil then
self.ActiveMDIChild.close;
就可以关闭了。不用定义TFrom变量来记忆当前子form了,除非另有需求。5. 这种layout的话,就不那么方便了。因为你还有两个splitter呢。
能控制吗?试过才知道。另外,我也是菜鸟一只。
我的回答,大部分也是即时摸索出来的,自己也有收获。
大家交个朋友,共同学习。
2. 我明白了你的意思。如果在C语言中,就是 p=&form; form = NULL; if (*p==NULL)
只是我不明白TFormN不是类吗,能对以它为类型的对象赋nil吗,create返回的是对象本身还是指向对象的指针,在C语言中返回的是对象的指针。
3、4、5没感觉,反正不是非解决不可,先跳过去再说。
6 我不知道我的理解与你说的是否一样。就是由菜单单击出现的所有form都是子form,而所讨论的出现在B区的几个form又是其中某一个子form的子form。如果子form可以有多级,也就是说,一个form可以作为上一级的子form,同时又作为下一级的父form,这种方法是行得通的。
同样,当你定义
var
frm:TForm;
...
frm:=formI;
的时候,frm只是FormI的引用而已。6. form应该是不能多级吧。 ...... (I)
看来这个问题上我没理解清楚你的意思。
你的意思应该是:
(A) mainform每个菜单项打开一个对应的form;
(B) 打开对应form时,关闭已有的form;
(C) 某个菜单项对应的form是MDIForm;
(D) 菜单项对应的form不能showmodal;
(E) 由(I),mainform不能是MDIForm
Question: 怎么实现(B)? 我现在的理解有没有错?如果没错,我的想法如下:
(i) 在mainform定义一个Public的CurrentForm:TForm;
(ii) 创建mainform的子form用这样的代码:
if CurrentForm <> nil then CurrentForm.Close;
CurrentForm:=Tform3.Create(self);
CurrentForm.Show;
(iii)各子form use mainform
(iv) 子form的OnClose事件中
action:=caFree;
mainform.CurrentForm:=nil;
我应该如何设置mainform、formi和formij的formstyle。
如果mainform、formi是normal,而formij是child,能保证formi始终在mainform的客户区中吗?
如果mainform是normal,而formi和formij是child,那formij怎么知道它的父窗口应该是formi,而不是mainform。
mainform
/ | \
form1 formi formN
/ | \
formi1 formij formiM
2. mainform也许可以用MDIForm。(我没试过)3. 整理一下本帖中的绝大部分问题(也许还有没理解透的)的思路如下:
A). mainfrom对formL,formI,formN的调用,采用我上贴的解决方法。
即:用CurrentForm来记住当前窗体
B). formI对formI0, formI1, ... ,formIn的调用,还是采用前述用Panel作parent的想法。
C). 平铺的控制只好自己写罗
简单的两个水平、垂直我已经测试过了
procedure TForm2.Button1Click(Sender: TObject);
var
i:integer;
begin
for i:=0 to panel2.ControlCount-1 do
with Panel2.Controls[i] do
Align:=alNone;
for i:=0 to panel2.ControlCount-1 do
with Panel2.Controls[i] do
begin
Width:=Panel2.ClientWidth div panel2.ControlCount;
//Width:=Panel2.ClientWidth;
Height:=Panel2.ClientHeight;
//Height:=Panel2.ClientHeight div panel2.ControlCount;
Align:=alLeft;
//alTop
end;
end;
愿闻其详,就本帖说说。我愿另外开贴给分。
敬请赐教,分不是问题。
主要的不便是:没有OnCreate/OnClose/OnShow(有OnResize)事件。1. mainform对子form的控制可以用frame,也许方便一点,差别不大。如:
private
{ Private declarations }
frame:TFrame; ...
if frame<>nil then frame.Free;
frame:=TframeI.Create(self); //I=0..n
frame.Parent:=Self;
frame.Align:=alClient;
frame.Show;
//类似form的控制。不用写form.OnClose。2. 但是frame相关的数据操纵,个人觉得不如form。
frameIJ可能由用户关闭,也可能由frameI(formI)关闭。
这时frameIJ数据的保存,该放在哪儿呢?
/ | \
form1 formi formN
/ | \
formi1 formij formiM如上图所示,程序中的form分为两级。
第一级的N个form共用同一个非客户区(菜单和工具栏),用户登录后将出现form1,日常运行时则通过单击菜单进行N个form之间的切换,任何时刻有且仅有一个第一级form。
在第一级的form中,有的只有它自己一个窗口,有的则还有自己的子窗口。 |
A | B
|
________|_________ C如上图所示,A、B、C共同构成有子窗口的第一级formi的客户区,它们之间的相对大小可由用户动态调整。
formi的子窗口formij只能局限于B区,其数目是由用户实际的操作(双击A区中treeview的item,此时增加一个formij;和主动单击formij的关闭按钮,此时相应的formij被关闭)所决定的,没有事先的限制(可以为0到无穷)。
每个formij在启动时读数据库,在关闭时写数据库,在formi因为用户单击了其它菜单项而被替换和因为主程序被关闭而被关闭时也要写数据库。希望能实现批量写数据库,例如不是在formij关闭时写数据库,而是在formi被关闭时写数据库,这样速度可能会快一些。
对于B区中的formij,要求在B的范围内支持层叠和平铺操作(不能超出B的边界),并且希望在B区能有一个独立的工具栏,即如右下图所示。 mainframe's toolbar
mainframe's toolbar | B's toolbar
| A | B
A | B _____|_______
_________|________请各位朋友多多指教,本人不甚感激。
主要的不便是:没有OnCreate/OnClose/OnShow(有OnResize)事件。贴一个小元件做补丁:unit FrameMove;interfaceuses
SysUtils, Classes, Controls, Forms, Dialogs;type
TFrameQueryEvent = procedure(Sender: TObject; var Enable: Boolean) of Object; TFrameMove = class(TComponent)
private
{ Private declarations }
FParentLeft: Integer;
FParentTop: Integer;
FOnInsertQuery: TFrameQueryEvent;
FOnRemoveQuery: TFrameQueryEvent;
FOnInsert: TNotifyEvent;
FOnRemove: TNotifyEvent;
function GetFrame: TFrame;
function GetIsInsert: Boolean;
procedure SetParentLeft(const Value: Integer);
procedure SetParentTop(const Value: Integer);
protected
{ Protected declarations }
function CanInsert: Boolean; virtual;
function CanRemove: Boolean; virtual;
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
function InsertFrame(FrameParent: TWinControl): Boolean;
function RemoveFrame: Boolean;
property Frame: TFrame read GetFrame;
property IsInsert: Boolean read GetIsInsert;
published
{ Published declarations }
property ParentLeft: Integer read FParentLeft write SetParentLeft default 0;
property ParentTop: Integer read FParentTop write SetParentTop default 0;
property OnInsertQuery: TFrameQueryEvent read FOnInsertQuery write FOnInsertQuery;
property OnRemoveQuery: TFrameQueryEvent read FOnRemoveQuery write FOnRemoveQuery;
property OnInsert: TNotifyEvent read FOnInsert write FOnInsert;
property OnRemove: TNotifyEvent read FOnRemove write FOnRemove;
end;procedure Register;implementationprocedure Register;
begin
RegisterComponents('User', [TFrameMove]);
end;{ TFrameMove }function TFrameMove.CanInsert: Boolean;
begin
Result := not IsInsert;
if Result and Assigned(OnInsertQuery) then
OnInsertQuery(Self, Result);
end;function TFrameMove.CanRemove: Boolean;
begin
Result := True;
if Assigned(OnRemoveQuery) then
OnRemoveQuery(Self, Result);
end;constructor TFrameMove.Create(AOwner: TComponent);
begin
if AOwner is TFrame then inherited Create(AOwner)
else ShowMessage('TFrameMove必须放在TFrame元件上.');
end;function TFrameMove.GetFrame: TFrame;
begin
Result := TFrame(Owner);
end;function TFrameMove.GetIsInsert: Boolean;
begin
Result := Frame.HasParent;
end;function TFrameMove.InsertFrame(FrameParent: TWinControl): Boolean;
begin
Result := CanInsert and Assigned(FrameParent);
if Result then
begin
Frame.Parent := FrameParent;
if ParentLeft <> 0 then Frame.Left := ParentLeft;
if ParentTop <> 0 then Frame.Top := ParentTop;
if Assigned(OnInsert) then OnInsert(Self);
end;
end;function TFrameMove.RemoveFrame: Boolean;
begin
if IsInsert then
begin
Result := CanRemove;
if Result then
begin
Frame.Parent := nil;
if Assigned(OnRemove) then OnRemove(Self);
end;
end else Result := True;
end;procedure TFrameMove.SetParentLeft(const Value: Integer);
begin
if FParentLeft <> Value then
begin
FParentLeft := Value;
if IsInsert then Frame.Left := Value;
end;
end;procedure TFrameMove.SetParentTop(const Value: Integer);
begin
if FParentTop <> Value then
begin
FParentTop := Value;
if IsInsert then Frame.Top := Value;
end;
end;end.
这个思路很好,佩服的很。学习中。
OnInsert/OnRemove事件应该是弥补OnCreate/OnClose事件的吧。
可是测试时,没有触发这两个事件啊。是不是还有什么bug。