控件的 Owner 和 Parent 有什么区别?

12

我对Delphi VCL控件的两个属性有点好奇。

每个组件在运行时都有OwnerParent这两个属性。谁能帮助我理解它们之间的区别?它们如何被Windows用于显示控件或窗体?


2
将一个窗体的“Parent”属性设置为另一个窗体,你就会看到结果了;-) - TLama
1个回答

28

所有者

所有者TComponent中引入的属性,所有者本身具有TComponent类型。 所有者主要用于管理设计组件的生命周期。也就是说,您在表单设计器(或其他设计表面)上放置并完全由框架管理生命周期的组件。 文档中提到:

指示负责流式传输和释放此组件的组件。

创建窗体时,流式传输框架会解析.dfm文件并实例化其中列出的组件。这些组件通常使用指定为该窗体的所有者创建。

在组件的生命周期的另一端是销毁。当一个组件被销毁时,它也会销毁所有拥有的组件。考虑一个具体的例子,一个 TButton 放置在设计时的 TForm 上。流式框架创建按钮并将其 Owner 设置为该表单。作为 TComponent 的后代,该表单维护着它拥有的所有组件的列表。当该表单被销毁时,它遍历该拥有组件列表并销毁它们。按钮以这种方式被销毁。
这其中有许多细节:
  • 组件不需要由表单拥有。例如,运行时创建的组件由您传递给构造函数的任何组件拥有。
  • 组件不需要拥有者,您可以向构造函数传递 nil。在这种情况下,程序员负责销毁该组件。
  • 组件的所有权可以在其生命周期中更改。
因为流式框架实例化组件,所以 TComponent 的构造函数被声明为虚函数:
constructor Create(AOwner: TComponent); virtual;

如果您派生自TComponent的子类,并希望该派生组件放置在设计表面上,则必须遵守此虚拟构造函数。如果您在TComponent的子类中定义了构造函数,则必须重写此虚拟构造函数。
值得指出的是,Win32有一个完全不同的窗口所有者概念,不应与VCL中同名的概念混淆。Windows documentation说:

Owned Windows

一个重叠或弹出窗口可以由另一个重叠或弹出窗口拥有。被拥有会对窗口施加几个限制。 - 拥有窗口始终位于其所有者之上。 - 当所有者被销毁时,系统会自动销毁所拥有的窗口。 - 当所有者最小化时,所拥有的窗口将被隐藏。

只有重叠或弹出窗口才能成为所有者窗口;子窗口不能成为所有者窗口。

在VCL术语中,这个概念通过PopupParent属性进行公开。该属性是在Delphi 7之后引入的,因此不可用。在Delphi 7中,框架设置窗口所有者,并且没有简单的机制可以覆盖框架的选择。如果您确实需要影响窗口所有权,则必须覆盖CreateParams并设置Params.WndParent。不幸的是,在Delphi 7中,VCL处理所有权存在一些问题,有时需要深入研究这些略带血腥的细节。
为了说明混淆的容易程度,VCL的documentation说:

WndParent: 父窗口的窗口句柄。这与父控件的Handle属性相同。

这是完全错误的。对于顶级窗口来说,这是所有者而不是父窗口。

父控件

ParentTControl 中定义的属性,类型为 TWinControl。该属性广泛用于公开 Win32 的父子控件概念。Windows 文档 中说:

一个窗口可以有一个父窗口。具有父级的窗口称为子窗口。父窗口提供用于定位子窗口的坐标系统。拥有父窗口会影响窗口外观的某些方面;例如,子窗口被剪切以使其任何部分都不会出现在其父窗口的边框外。没有父级或其父级为桌面窗口的窗口称为顶级窗口。

实际上,VCL 中的 Parent 属性直接映射到 Win32 的父级概念。

请注意,Parent 是在 TControl 中定义的。现在,TControl 不是窗口化的,因此在 Win32 意义上,TControl 不是子控件,因为 Win32 窗口的子控件本身就是窗口。因此,具有定义的 ParentTControl 是 VCL 意义上的子控件,称为非窗口化子控件。这些非窗口化控件会作为其父控件的绘图处理程序的一部分进行绘制。这样的控件的典型示例是 TLabel
请注意,当销毁一个窗口化控件(即 TWinControl 的后代)时,它也会销毁其所有子控件。 TWinControl 后代可以使用 ControlCountControls[] 属性枚举其子控件。这两个属性都可以枚举窗口化和非窗口化子控件。

1
非常有用!我一直在苦苦挣扎于父子系统,而Delphi的手册根本没有帮助。 - Gabriel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接