首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > .NET > .NET >

低级有关问题,动态创建panel 释放时 是否需要释放panel上动态创建的东西

2012-05-24 
低级问题,动态创建panel 释放时 是否需要释放panel上动态创建的东西?比如 我动态创建一个panel 在这个pane

低级问题,动态创建panel 释放时 是否需要释放panel上动态创建的东西?
比如 我动态创建一个panel 在这个panel上再次创建一个按钮 和图片等, 点击按钮释放 panel
 
就是不知道在释放panel的释放是否需要释放容器内的控件,包括按钮本身
大概代码

Delphi(Pascal) code
procedure TForm1.Button1Click(Sender: TObject);  var t:TPanel;    b:TButton;    img:TImage;  begin  t:=TPanel.Create(Self);  //创建panel  t.Parent:=Self;  t.Width:=300;  t.Height:=50;  t.Top:=0;  t.Left:=0;  b:=TButton.Create(t);   //在panel上创建一个按钮  b.Parent:=t;  b.Left:=0;  b.Top:=0;  img:=TImage.Create(Self);  //  在panel上创建一个img  img.Parent:=t;  img.Left:=30;  img.Top:=0;  img.Picture.LoadFromFile('c:\1.bmp');  b.OnClick:=Button2.OnClick; //释放事件end;procedure TForm1.Button2Click(Sender: TObject);var     b:TButton;begin     b:=TButton(Sender);  //这里是否要先释放父控件上的动态创建的东西???????? b.Parent.Free;  //释放父控件,也就是创建的panel end;


[解决办法]
不好意思,可能是我的鼠标有问题,回了两次了,抱歉。

其实,上述的问题,我们可以来个测试:
Delphi(Pascal) code
procedure TForm1.Button1Click(Sender: TObject);var Panel:TPanel;    Button:TButton;begin  Panel:=TPanel.Create(self);  Panel.Parent:=Form1;  Button:=TButton.Create(Panel);  Button.Parent:=Panel;  showmessage('动态建立了Panel和Button');  Panel.Free;  if Assigned(Panel) then showmessage('Panel释放了,但它的指针还在');  try    Button.Free; //如这句能不出错,证明它还在    showmessage('Panel释放了,但Button还没释放。');  except    showmessage('Button已经不存在.');  end;  Panel:=TPanel.Create(self);  Panel.Parent:=Form1;  Button:=TButton.Create(Panel);  Button.Parent:=Panel;  showmessage('再次动态建立了Panel和Button');  FreeAndNil(Panel);  if not Assigned(Panel) then showmessage('Panel释放了,它的指针也同时释放了');  try    Button.Free;    showmessage('Panel释放了,但Button还没释放。');  except    showmessage('Button已经不存在.');  end;  if Assigned(Button) then    showmessage('Button虽然不在了,但它的指针还在')  else    showmessage('Button不在了,它的指针也不存在');  Button:=nil;  if Assigned(Button) then    showmessage('Button的指针还在')  else    showmessage('Button的指针不在了');end;
[解决办法]
var Panel:TPanel;
Button:TButton;
begin
Panel:=TPanel.Create(self);
Panel.Parent:=Form1;
Button:=TButton.Create(self);
Button.Parent=Panel;
Panel.Free;
end;

只要释放Panel; Button对象也跟着会释放;也就是 如果一个控件有父对象 当父释放时候 子也必然会释放。

一下是VCL 源码:
设置父对象时候 调用的 一段源码
procedure TWinControl.Insert(AControl: TControl);
begin
if AControl <> nil then
begin
if AControl is TWinControl then
begin
ListAdd(FWinControls, AControl);
ListAdd(FTabList, AControl);
end else
ListAdd(FControls, AControl);
AControl.FParent := Self;
end;
end;

父控件释放的时候的 源码
destructor TWinControl.Destroy;
var
I: Integer;
Instance: TControl;
begin
Destroying;
if FDockSite then
begin
FDockSite := False;
RegisterDockSite(Self, False);
end;
FDockManager := nil;
FDockClients.Free;
if Parent <> nil then RemoveFocus(True);
if FHandle <> 0 then DestroyWindowHandle;
I := ControlCount;
while I <> 0 do
begin
Instance := Controls[I - 1];
Remove(Instance);
Instance.Destroy;
I := ControlCount;
end;
FBrush.Free;
{$IFDEF LINUX}
if FObjectInstance <> nil then WinUtils.FreeObjectInstance(FObjectInstance);
{$ENDIF}
{$IFDEF MSWINDOWS}
if FObjectInstance <> nil then Classes.FreeObjectInstance(FObjectInstance);
{$ENDIF}
inherited Destroy;
end;


function TWinControl.GetControlCount: Integer;
begin
Result := 0;
if FControls <> nil then Inc(Result, FControls.Count);
if FWinControls <> nil then Inc(Result, FWinControls.Count);


end;


 


[解决办法]
这里有两个属性需要注意
1:Owner
对于所有从TComponent继承下来的对象都有Owner属性,该属性值是作为构造函数的参数Create(Owner: TComponent)构造时被赋值。Owner指的是容器对象,当被添加到容器中后,容器释放前,会自动释放中间所有的成员。也就是说,当一个对象在构造时写成Create(Owner),则Owner被释放时,会自动释放该对象,成员对象不需要手工释放。

对象在构造时可以不指定容器对象,写成Create(nil),则该对象需要注意手工释放。

如果成员对象在容器之前释放,例如,Item= TItem.Create(Owner);Item在Owner之前被释放,容器Owner随后释放时,是不会出错的,因为成员Item在释放的时候,会在容器Owner列表中搜索自己,搜索到自己后从列表中移除。

如果需要在对象构造之后改变其容器Owner,使用容器Owner的RemoveComponent从Owner中移除自己,调用新容器的InsertComponent,将自己加入到新容器。

2:Parent
该属性虽然被定义在TControl中,但是在TWinControl中被使用。该属性的本意是用来控制UI控件在显示时是属于哪个控件之内,也就是所谓的控件容器control container。注意,这里和上面提到的Owner并不相同,Parent不负责释放其包含的控件对象。

Parent属性可以直接被取值赋值,从而改变控件的包含关系。注意,当Parent发生改变后,控件位置属性的坐标也会改变为以父控件的相对坐标,即子控件的Top Left 的起始点是Parent的左上角,改变Owner不会影响到该属性的值。

楼主贴出的代码中,如果你需要判定一个对象变量的是否被释放的话,建议你在释放的时候写成FreeAndNil(Obj),而不是Obj.Free,这样的好处是你可以使用Obj=nil这样的语句来判定Obj是否被释放。

函数Assigned()一般是用来判定函数指针(函数变量)是否是空指针,当用它来判定对象时,等同于Obj=nill,如果Obj不是使用FreeAndNil释放的时候,Assigned()也可能判定不正确。

热点排行