MainFrm和动态创建的Form中使用Frame遇到地有趣问题. (100分)

  • 主题发起人 主题发起人 千中元
  • 开始时间 开始时间

千中元

Unregistered / Unconfirmed
GUEST, unregistred user!
现在以Form1为MainFrm.
菜单1的Onclick事件中:
代码:
 if Assigned(Frame) then Frame.Free;
   Frame :=TFrame2.Create(Application);
   Frame.Align := alleft;
   Frame.Parent := Form1;
可以运行无限次数,无异常.

现在让Frame出现在动态创建的Form3中.菜单2 Onclick事件如下:

代码:
Form3:= TForm3.Create(Application);
  try
  if Assigned(Frame) then Frame.Free
 //FreeAndNil(Frame);
  ------菜单2事件多次触发,第二遍时候上一行代码中Frame.Free出错了
  ------如果改为 Frame := nil;则可以运行无限多次无错误;
  Frame := TFrame2.create(Form3);
  Frame.Align := AlLeft;
  Frame.Parent := Form3;
  Form3.showmodal;
  finally
   Form3.free;
  end;

Form3.Free后重新创建,为何导致了和MainFrm 使用Frame上的这种差异?
我跟踪了一下,Form3.Free后Frame 对象仍然存在,按照我以前的观念,
"
Frame := TFrame2.create(Form3);
Frame.Align := AlLeft;
Frame.Parent := Form3;"
-----这三句代码应该可保证Form3.Free以后,以Form3为容器的控件都要
自动释放的.

不好意思,看来要重新学delphi了[:)]
 
finally
Form3.free;
Form3 := nill;
//Or FreeAndNil(Form3);
end;[/code]
 
[原文Begin]
按照我以前的观念,Form3.Free以后,以Form3为容器的控件都要自动释放的.
[原文End]

对啊。确实如此。
if Assigned(Frame) then Frame.Free
这句是看 Frame 是不是为 nil ,
Frame 做为对象的指针,当被指向的对象被 Free 掉后,Frame 不一定是 nil ,
如果 Frame 不是 nil ,则 if Assigned(Frame) then Frame.Free;这句将
被执行,执行后 Frame.Free 就是在对根本不存在的对象进行操作(Frame 已随 Foem3 被 Free)。
所以将会出现错误。但如果将 Frame 置成 nil ,这是针对指针变量的操作,当然没有错误
了。
于是可以这样认为,在本代码中,
if Assigned(Frame) then Frame.Free
这句即便改成了
if Assigned(Frame) then Frame:=nil;也是没有意义的。
干脆删除掉这句,就没有问题了。
------ 特此回复
1.两个过程中创建的 Frame 最好使用各自的名字,如 Frame,Frame1:TFrame;
2.菜单 2 Onclick事件如下:
Form3:= TForm3.Create(Application);
try
Frame1 := TFrame2.create(Form3);
Frame1.Align := AlLeft;
Frame1.Parent := Form3;
Form3.showmodal;
finally
Form3.free;
Frame1:=nil;
end;
 
还有。如果代码确实需要使用 if Assigned(Frame) then Frame.Free;来清理内存的话,
为便于多个过程独立处理,可以针对上面的代码作例外处理,就是当 Frame.Free 出错
时,在 except 块中将 Frame 改成 Frame:=nil 就行了。这样就可以跳过执行上面的代
码了。
 
to 千中元,
按照我以前的观念,Form3.Free以后,以Form3为容器的控件都要自动释放的.

你这句话说得不准确,
应该是,每个从组件(TComponent)继承的对象(包括,所有的组件,控件,窗口和Frame)
在被Free时都会释放他所拥有的所有从组件继承而来的对象,

容器(Container)和拥有者(Owner)是不同的概念
容器是对控件来说的(TControl继承而来的对象),控件的容器是被Parent属性所指定的
拥有者是对组件(TComponent继承而来的对象,当然组件是控件的超集)来说的,
对应于组件的Owner属性,
通常组件被创建的时候,通过构造函数Create(AOwner: TComponent)
传递了拥有者的参数,表示新创建的对象被参数中的对象所拥有,
拥有者将扮演最终释放自己拥有的对象的角色,
所以你的对象将最终在他的拥有者被释放的时候释放,所以你不用担心,
这个对象会不会被释放,
一个对象的变量仅仅是对一个对象的引用而已,相当于一个指针
可以同时定义多个变量,同时指向这个对象,

当然,如果这个对象被释放了(可能是他的拥有者干的,也可能是你干的),
那么这些变量仍然指向这个对象生前的地址,除非你把他们置空

所以你的Frame可以用一个临时变量,
创建后也不用管它的死活了,系统的内部机制会自动处理,
他将于他的拥有者共存亡
 
to 小雨哥,
你的代码可以改为
Form3:= TForm3.Create(Application);
try
with TFrame2.create(Form3) do
begin
Align := AlLeft;
Parent := Form3;
end;
Form3.showmodal;
finally
FreeAndNil(Form3);
end;
 
Form3:= TForm3.Create(Application);
try
if Assigned(Frame) then
try
Frame.Free
//FreeAndNil(Frame);
except
end;
------菜单2事件多次触发,第二遍时候上一行代码中Frame.Free出错了
------如果改为 Frame := nil;则可以运行无限多次无错误;
Frame := TFrame2.create(Form3);
Frame.Align := AlLeft;
Frame.Parent := Form3;
Form3.showmodal;
finally
Form3.free;
end;
 
TO:LiChaoHui
你的修改看到了。很好的。
 
to plane822,

你的上面的代码是什么意思呀?
完全画蛇添足,多此一举,并且还会出错
 
???
老千?还不结束?我先答的啊~~~~~~~~~~
关键就是每次Free以后要置nil,不然是没有办法判断其是否已经被创建的。
这也是D5中引进FreeAndNil的原因吧……
另外:
如果有兴趣看看其原代码的话(汇编)//长那么大就看过D的这段汇编,郁闷
Free就是if not nil the destroy;所以:
for i := 0 to 13 do Form3.free会出错。而
for i := 0 to 13 do begin
Form3.free;Form3 := nil
//FreeAndNil(Form3);没实验过
end;//就不会出错了
 
另外解释一下Assign:) //这个分我要定了,不准抢
assign的代码类似这样:
function Assign(obj:TObject):Boolean;
begin
Result := not obj = nil;
end;

也就是说,你用if xx=nil then和if assigned(xx) then是类似的
也无法检测出Free了但是不置nil的情况。

所以,最后,强烈建议,一律FreeAndNil(xx);
如果要用D5以前版本,自己写个函数也不难。要么自己养成xx.free;xx:=nil的习惯
 
忘记说了,按照你上面的写法还是有问题的:
需要在枪毙Form3时把Frame3置nil
 
老千,下次又这么便宜的问题记得先告诉我啊,肯定比 CJ 大虾抢得快:)
 
看看OBject PASCALL 吧,不要总是讨论这样的问题,浪费时间,
我现在也在使用FRAM 构建一个MIS小系统,主功能的实现在主窗口的CLIENT区,有几个FRAM
动态创建。关于FRAM的创建和析构全部由主窗体的一个统一的函数控制 --- 应用控制台函数。
很稳定名位任何问题的。

把FRAM用好了可以作出很漂亮的程序的。

希望与大家交流 : Email :snguobin@sohu.com
 
小雨哥的解释不错
 
我在使用动态创建控件的中间也遇到过这样的问题,不光是frame。
同意小雨哥的。
记住要使用FreeAndNil();
d6中的源码z
procedure FreeAndNil(var Obj);
var
Temp: TObject;
begin
Temp := TObject(Obj);
Pointer(Obj) := nil;
Temp.Free;
end;

 
接受答案了.
 
后退
顶部