24

Delphi 组件有CreateWndand CreateWindowHandle(and DestroyWndand DestroyWindowHandle)。他们都打算被后代覆盖,对吧?并且不打算被底层 VCL 实现调用?

它们之间有什么区别;什么时候应该覆盖它们中的任何一个?

4

4 回答 4

42

到目前为止,这里的大多数答案都差不多,你最好听从他们的建议。但是,这个故事还有更多内容。对于您何时会覆盖其中一个或另一个的具体问题,我将尝试简要介绍一下。

创建参数();

一般来说,大多数时候你真正需要做的就是重写 CreateParams()。如果您只想对现有控件类进行子类化(还记得 Windows 风格的“子类化吗?”请参阅 Petzold 关于 Windows 编程的开创性工作)并将其包装在 VCL 控件中,您可以从 CreateParams 执行此操作。您还可以控制设置的样式位和其他各种参数。我们使创建“子类”的过程变得非常简单。只需从您的 CreateParams() 方法调用 CreateSubClass()。有关 TCheckBox 或 TButton 等示例,请参阅核心 VCL 控件。

CreateWnd();

如果您需要在创建窗口句柄后对其进行更多操作,您将覆盖这个。例如,如果您的控件是某种列表、树或其他需要创建后配置的控件,您可以在此处执行此操作。调用继承的 CreateWnd,当它返回时(如果您从 CreateWnd 返回,您知道您有一个有效的句柄,因为如果出现问题,它将引发异常),只需应用您的额外魔法。一个常见的场景是获取缓存在实例 TStrings 列表中的数据,并将其实际移动到底层窗口控件中。TListBox 就是一个典型的例子。

创建窗口句柄();

我不得不去刷新我对这个的记忆,但似乎这是一个很少,如果有的话,被覆盖。在 VCL 本身内部的少数情况下,它似乎用于使用某些控件(例如 TEdit 和 TMemo)来解决特定的 Windows 版本和区域设置异常。另一个更明确的案例是 TCustomForm 本身。在这种情况下,它支持旧的 MDI(多文档接口)模型。在这种情况下,无法使用普通的 CreateWindowEx() API 创建 MDI 子项,您必须向 MDI 父框架发送消息才能实际创建句柄。因此,覆盖此方法的唯一原因是,如果创建句柄的实际过程是通过与旧的久经考验的 CreateWindowEx() 完全不同的方式完成的。

我确实注意到您的问题只是询问创建过程,但在某些情况下,对于句柄破坏和有时围绕句柄重新创建的“巫毒”,有相应的方法被覆盖。但这些是应该单独讨论的其他主题:-)。

于 2009-02-24T21:44:54.333 回答
4

CreateWnd 首先调用 CreateParams,然后使用创建的 Params 调用 CreateWindowHandle。通常,您将覆盖 CreateWnd 和 CreateParams 而不是 CreateWindowHandle。

我希望这有帮助!

于 2009-02-24T18:29:06.893 回答
3

谁做什么:
CreateWnd是为 WinControl 创建完整窗口的总承包商。
首先,它必须通过调用CreateParams为 WindowClass 设置所需的属性,并确保它已正确注册。
然后它通过调用从操作系统返回结果句柄的CreateWindowHandle来获取实际创建的窗口。
之后,我们有一个能够处理消息的有效窗口,CreateWnd进行最后的修饰,调整不同的视觉方面,如大小、字体等。

CreateWnd 完成后, CreateHandle还完成了稍后的步骤,以帮助 VCL 管理其窗口(标识、亲子关系……)。

于 2009-02-24T20:39:20.670 回答
0

我敢肯定,最终答案只能来自参与创建 VCL 的人员(Allen?),但恕我直言,应该覆盖调用链中责任最小/最低的虚拟方法。这就是为什么我总是覆盖CreateParams()CreateWindowHandle()。这看起来很合适,因为它们都由CreateWnd()调用,并且都只做一件特殊的事情。

最后,这可能是一个偏好问题。

于 2009-02-24T20:08:38.573 回答