Delphi组件有CreateWnd
和CreateWindowHandle
(以及DestroyWnd
和DestroyWindowHandle
)。它们都是为了让后代类覆盖,而不是为了除基础VCL实现外的调用而设计的?
它们之间有什么区别?应该在何时覆盖其中任意一个?
Delphi组件有CreateWnd
和CreateWindowHandle
(以及DestroyWnd
和DestroyWindowHandle
)。它们都是为了让后代类覆盖,而不是为了除基础VCL实现外的调用而设计的?
它们之间有什么区别?应该在何时覆盖其中任意一个?
目前这里的大部分答案都基本正确,你最好听从他们的建议。但是,这个故事还有更多内容。关于你具体的问题,即何时覆盖其中一个或另一个,我会尝试简要概括一下。
CreateParams();
通常情况下,你只需要覆盖CreateParams()方法即可。如果你想做的就是子类化(记得 Windows 风格的“子类化”吗?参见 Petzold 在 Windows 编程方面的开创性工作)现有的控件类并将其包装成 VCL 控件,就从CreateParams开始吧。你还可以控制设置哪些样式位和其他各种参数。我们已经使“子类”创建过程变得非常容易了。只需从CreateParams()方法中调用CreateSubClass()即可。例如,查看核心 VCL 控件,如 TCheckBox 或 TButton,就可以看到示例。
CreateWnd();
如果您需要在创建窗口句柄后对其进行更多操作,则可以覆盖此方法。例如,如果您有一个控件是一些列表、树形控件或其他需要后期配置的控件,您可以在此处进行配置。调用继承的 CreateWnd,当它返回时(如果从 CreateWnd 返回,则知道您有一个有效的句柄,因为如果出现问题,它将引发异常),只需应用您的额外魔法即可。常见情况是将缓存在 TStrings 列表实例中的数据实际移动到基础窗口控件中去。TListBox 就是一个经典的例子。
CreateWindowHandle();
我不得不回忆一下这个问题,但似乎很少甚至从未被覆盖。在VCL内部的少数情况下,它似乎用于解决一些控件(如TEdit和TMemo)在特定Windows版本和区域设置方面的问题。另一个更清晰的情况是在TCustomForm本身中。在这种情况下,它用于支持旧的MDI(多文档界面)模型。在这种情况下,无法使用常规的CreateWindowEx() API创建MDI子窗口,您必须向MDI父帧发送消息以实际创建该句柄。因此,仅在实际创建句柄的过程完全不同于旧的可靠的CreateWindowEx()时,才需要覆盖此方法。
我注意到您的问题只是询问创建过程,但是有一些相应的方法在某些情况下被覆盖,用于处理句柄销毁和有时涉及句柄重新创建的“巫术”。但这些都是其他要分别讨论的话题 :-).
CreateWnd首先调用CreateParams,然后使用创建的Params调用CreateWindowHandle。通常,您会重写CreateWnd和CreateParams而不是CreateWindowHandle。
希望这可以帮助您!
谁做什么:
CreateWnd 是创建WinControl完全形成窗口的总承包商。
首先,它必须通过调用CreateParams设置WindowClass所需的属性,并确保正确注册。
然后,通过调用CreateWindowHandle获取实际创建的窗口,该函数从操作系统返回结果句柄。
此后,我们有一个能够处理消息的有效窗口,CreateWnd 进行最后的修饰,调整不同的视觉方面,如大小、字体等。
还有一个稍后由 CreateHandle 完成的步骤,以帮助VCL管理其窗口(标识、父级等)。
我相信最终的答案只能来自于参与 VCL 创建的人(Allen?),但在我看来,应该重写责任最小/调用链最低的虚方法。这就是为什么我一直重写 CreateParams() 和 CreateWindowHandle()。这看起来很合适,因为它们都被 CreateWnd() 调用,并且都只做一件特殊的事情。
最终这可能只是个人喜好的问题。