您的问题并不是很有用,因为 - 一般而言 - 不鼓励将数据(或您的情况下的对象)存储在 GUI 控件中。另请参阅 David 关于如何更改设计的评论。
使这个问题变得有趣的是,组合框直接作为表单的子项与作为表单的另一个子项(在这种情况下为您的框架)的子项之间的区别。显然,组合框项目在调用该框架的析构函数之前被销毁。探索的明显替代方案是:覆盖Frame.BeforeDestruction
、覆盖Frame.DestroyWindowHandle
、覆盖Frame.DestroyWnd
或捕获WM_DESTROY
覆盖Frame.WndProc
,但在项目已经消失之前,它们都不会被调用。
接下来要尝试的是对组合框重复此操作。事实证明,当WM_DESTROY
到达组合框时,项目仍然存在。但是,请注意仅在控件真正被销毁时才捕获该消息,因为 VCL 可能会频繁地重新创建组合框。使用插入类 for 来实现它TComboBox
,如下所示:
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.
现在,回答您的问题:“这是更好的方法吗?”
是的,因为它提供了在框架级别上破坏对象的保证。换句话说:您不必记住为每个实例分别处理这个问题。
不,不是,因为此解决方案要求在任何情况下都允许释放组合框中的对象,这将使用限制在不必要的额外边界。
那么,这个答案有用吗?好吧,如果它阻止您使用当前的方法,那么它就是。
Parent
此外,我还通过在包含表单处理程序中将框架的属性设置为 nil找到了另一种选择OnDestroy
:
procedure TForm2.FormDestroy(Sender: TObject);
begin
Frame1.Parent := nil;
end;
在这种情况下,您可以安全地销毁存储在框架析构函数内的组合框中的对象。但是这个解决方案比你现在的解决方案更糟糕,因为它不是描述性的。然后就好Frame1.FreeComboObjects
很多了。