首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在哪里释放动态分配的TFrame组件的对象?

在哪里释放动态分配的TFrame组件的对象?
EN

Stack Overflow用户
提问于 2013-02-24 01:18:58
回答 4查看 1.9K关注 0票数 7

我有一个包含TFrame的表单。TFrame包含一个动态填充的ComboBox。每个ComboBox条目都有一个关联的对象。在调用TFrame的重写析构函数时,ComboBox中的项已经被清除,而没有释放其关联的对象。无论是在设计器视图中将ComboBox拖放到窗体上,还是在代码中以nil或TFrame作为其所有者动态创建它,都会发生这种情况。我目前使用包含TFormOnDestroy事件来调用包含的TFrame的清理过程。

有没有一种更好的方法不需要TFrame容器显式的过程调用?理想情况下应该在哪里释放动态添加到ComboBox的对象?

EN

回答 4

Stack Overflow用户

发布于 2013-02-24 23:36:55

您可以说,当调用TFrame的析构函数时,ComboBox的项已经被清除。事实并非如此,ComboBox项永远不会被清除。当物品被ComboBox销毁时,它们的计数只有0。

当您退出应用程序时,VCL会销毁包含frame和ComboBox的窗体,本机ComboBox控件也会被操作系统销毁,因为它被放置在被销毁的窗口中。当您稍后访问这些项以释放框架析构函数中的对象时,VCL必须重新创建一个本机ComboBox控件,使项计数为0。

我提出的解决方案很简单。不要将框架释放给框架,相反,在表单的OnDestroy事件中销毁框架。这是在窗体的底层窗口被销毁之前,因此您将能够访问您的对象。

表单单元

代码语言:javascript
运行
复制
procedure TMyForm.FormDestroy(Sender: TObject);
begin
  MyFrame.Free;
end;

帧单位

代码语言:javascript
运行
复制
destructor TMyFrame.Destroy;
var
  i: Integer;
begin
  for i := 0 to ComboBox1.Items.Count - 1 do
    ComboBox1.Items.Objects[i].Free;
  inherited;
end;
票数 8
EN

Stack Overflow用户

发布于 2013-02-24 23:50:27

您可以像这样使用TFrameWM_DESTROY处理程序:

代码语言:javascript
运行
复制
unit Unit2;

interface

uses
  Windows, Messages, SysUtils, Classes, Controls, Forms, StdCtrls;

type
  TFrame1 = class(TFrame)
    ComboBox1: TComboBox;
  private
    procedure WMDestroy(var Msg: TWMDestroy); message WM_DESTROY;
    procedure FreeComboBoxItems;
  public
    constructor Create(AOwner: TComponent); override;
  end;

implementation

{$R *.dfm}

constructor TFrame1.Create(AOwner: TComponent);
begin
  inherited;
  // Add some object items to the ComboBox
  ComboBox1.AddItem('a', TButton.Create(nil));
  ComboBox1.AddItem('b', TMemoryStream.Create);
  ComboBox1.AddItem('c', TList.Create);
end;

procedure TFrame1.WMDestroy(var Msg: TWMDestroy);
begin
  // Make sure the TFrame is actually destroying - not recreated
  if (csDestroying in ComponentState) then
    FreeComboBoxItems;
  inherited;
end;

procedure TFrame1.FreeComboBoxItems;
var
  I: Integer;
begin
  OutputDebugString('TFrame1.FreeComboBoxItems');
  with Self.ComboBox1 do
    for I := 0 to Items.Count - 1 do
    begin
      OutputDebugString(PChar(Items.Objects[I].ClassName + '.Free'));
      Items.Objects[I].Free;
    end;
end;

end.

另一种选择是为整个应用程序创建一个基本祖先TAppBaseForm类和一个TAppBaseFrame,并将所有表单派生为TAppBaseForm,将所有框架派生为TAppBaseFrame。这样,TAppBaseForm就可以通过TAppBaseForm.FormDestroy事件处理程序通知它的所有子TAppBaseFrame所有者窗体已被销毁。此时,ComboBox项仍然有效(正如Sertac Akyuz的answer所描述的那样)。

票数 8
EN

Stack Overflow用户

发布于 2013-02-24 21:29:41

你的问题并不是很有用,因为一般来说,不鼓励在GUI控件中存储数据(在您的情况下是对象)。另请参阅David关于如何更改设计的评论。

然而,让这个问题变得有趣的是,组合框直接是一个窗体的子级和该窗体的另一个子级(在本例中是您的框架)的子级之间的区别。显然,组合框项在调用该框架的析构函数之前就被销毁了。显而易见的替代方法是:覆盖Frame.BeforeDestruction、覆盖Frame.DestroyWindowHandle、覆盖Frame.DestroyWnd或在覆盖的Frame.WndProc中捕获WM_DESTROY,但在这些项已经消失之前都不会调用它们。

下一件要尝试的事情是对组合框重复此操作。事实证明,当WM_DESTROY到达组合框时,项目仍然在那里。但是,当控件真的被销毁时,要注意捕捉到该消息,因为VCL可能会频繁地重新创建组合框。使用TComboBox的插入类实现它,如下所示:

代码语言:javascript
运行
复制
unit Unit2;

interface

uses
  Windows, Messages, Classes, Controls, Forms, StdCtrls;

type
  TComboBox = class(StdCtrls.TComboBox)
  protected
    procedure WndProc(var Message: TMessage); override;
  end;

  TFrame1 = class(TFrame)
    ComboBox1: TComboBox;
  end;

implementation

{$R *.dfm}

{ TComboBox }

procedure TComboBox.WndProc(var Message: TMessage);
var
  I: Integer;
begin
  if (Message.Msg = WM_DESTROY) and (csDestroying in ComponentState) then
    for I := 0 to Items.Count - 1 do
      Items.Objects[I].Free;
  inherited WndProc(Message);
end;

end.

现在,回答你的问题:“这是一种更好的方式吗?”

是的,因为它提供了对象在框架级别的销毁的保证。换句话说:您不必记住为每个实例单独处理此问题。

不,它不是,因为这个解决方案要求允许组合框中的对象在任何情况下被释放,这限制了对不必要的额外边界的使用。

那么,这个答案有用吗?好吧,如果它阻止你使用你当前的方法,那么它就是。

此外,我还找到了另一种替代方法,在包含表单的OnDestroy处理程序中将框架的Parent属性设置为nil:

代码语言:javascript
运行
复制
procedure TForm2.FormDestroy(Sender: TObject);
begin
  Frame1.Parent := nil;
end;

在这种情况下,您可以安全地销毁存储在框架析构函数的组合框中的对象。但是这个解决方案比你现在的解决方案更糟糕,因为它不是描述性的。那么Frame1.FreeComboObjects就好多了。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15043297

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档