Delphi 在运行时创建复合控件(其他控件的父控件)

Delphi 在运行时创建复合控件(其他控件的父控件),delphi,Delphi,我有一段代码覆盖TStringGrid的就地编辑器和提示窗口。为此,我基于TStringGrid创建了自己的字符串网格,并使用TEdit作为内置编辑器,TPanel作为工具提示。在TMyStringGrid.Create构造函数中,我按如下方式初始化它们: Constructor TMyStringGrid.Create(); Begin inherited Create(AOwner); MyEditor:= TEdit.Create(Self); MyEditor.Paren

我有一段代码覆盖TStringGrid的就地编辑器和提示窗口。为此,我基于TStringGrid创建了自己的字符串网格,并使用TEdit作为内置编辑器,TPanel作为工具提示。在TMyStringGrid.Create构造函数中,我按如下方式初始化它们:

Constructor TMyStringGrid.Create();
Begin
  inherited Create(AOwner);
  MyEditor:= TEdit.Create(Self);  
  MyEditor.Parent  := Self;
End;
在这种情况下,所有者(主窗体)正在释放控件。我用了好几年,效果很好。 问题是,其他人认为程序员在实例化子控件时应该使用NIL而不是Self,然后在Destroy析构函数中手动释放它们。第二种方法似乎比第一种方法有巨大的优势,特别是当您动态创建大量子控件时(我的情况不是这样)。他们说,我的代码的另一个问题是,在Application.ProcessMessages调用之后,子控件可能会被释放,而应用程序可能仍然想要使用它们

所以,我应该让我的代码保持不变,还是应该手动创建并释放子控件? 是否有Borland的复合控制示例


德尔福7,赢XP

参考资料:

是的,您可以在不更改代码的情况下使用代码

There is a any Borland example of compound controls?
最好的例子是检查
TLabeledEdit
的实现

它正在构造函数中创建标签

  if Assigned(FEditLabel) then exit;
  FEditLabel := TBoundLabel.Create(Self);
  FEditLabel.FreeNotification(Self);
  FEditLabel.FocusControl := Self;

在这种情况下,没有理由通过nil而不是
Self
。AOOwner参数就是专门为此而存在的。好好利用它

创建控件并手动销毁它时,传递nil是有原因的,但情况完全不同:如果在函数中创建控件(通常是表单)。这是一种非常常见的模式,例如:

MyDialog := TMyDialog.Create(nil);
try
  result := MyDialog.ShowModal;
finally
  MyDialog.Free;
end;

在这里,您希望立即释放它,而不是等待当前表单被销毁,这可能要晚很多。但是当涉及到子组件时,您通常希望它们与父组件同时销毁,而不是稍后销毁,因此将
Self
传递给AOOwner,让VCL为您处理它。

考虑到该构造函数,网格实例由AOOwner拥有(通常是TForm或TFrame)。inplace编辑器由网格实例拥有并作为其父对象。我不知道ProcessMessages如何导致子对象的破坏,因为它们将在TMyStringGrid的破坏循环中被破坏。这是没有什么我可以看出该实现中的错误-我对我创建的组件使用相同的设计。在VCL上有所有权,以便在管理对象的生命周期时简化我们的生活。而不是推荐nil作为所有者的情况,如梅森的回答所示

在Mason显示的模式中,NIL的原因是,如果没有所有者,对象销毁将不会进入通知循环。如果您创建了大量手动处理的组件销毁,则需要确保所有者为零,否则在每个组件构造/销毁中都会执行大量代码(无需执行)。
许多月前,在(现已不复存在)的网络档案上有一份出色的白皮书。我觉得那篇文章发自About.com,我不知道是哪篇文章先发的。事实上,它们是同一篇文章-但是about.com不包括文章发布的日期-eagle software one是1999年的。谢谢+1.图案的名称是什么?谢谢+1.对了,贝勒迪特!在我问这个问题的那一刻,我完全忘记了TLabeledEdit:)