我在某些组件中使用了断点,并确定 AFTERCONSTRUCTION 称为 BEFORE LOADED 而不是 AFTER。
我也在 FORM 上做了同样的事情,并确定 AFTERCONSTRUCTION 被称为 AFTER LOADED 而不是 BEFORE。
请记住,AfterConstruction 是 TObject 中的一个方法,但 Loaded 不是。由此可见,Loaded 是由不一定按相对于 AfterConstruction 的特定顺序的代码生成的,因为 Loaded 实际上不是 TObject 的构造序列的一部分,而 AfterConstruction 是。
确实,如果您研究 RTL 源代码,您会发现 Loaded 甚至没有被 TComponent 的任何 self.method 调用,而是由正在读取 DFM 的流读取器调用,而且很可能在“所有者”组件的控制下发生。因此,我强烈建议它与 AfterConstruction 执行的关系并不能真正得到保证。它以特定顺序出现在表单中的事实是因为表单最有可能是启动流读取的组件。换句话说,Loaded 在表单中的 AfterConstruction 之前有点意外。
进一步的研究表明,包含以下代码的 NON-FORM 组件可能永远不会调用事件处理程序。
procedure Txxx.AfterConstruction; override;
begin
inherited AfterConstruction;
if Assigned(FOnCreate) then FOnCreate(Self);
end;
原因是AfterConstruction,如果在属性加载之前调用,会发现FOnCreate还没有赋值!
在这种情况下,你真的必须使用以下方法:
procedure Loaded; override;
begin
inherited Loaded;
if assigned(OnLoaded) then OnLoaded(self);
end;
就像我说的,这会为表单拥有的组件产生与表单本身不同的结果! TForm 组件通常是 DFM 流读取器的调用者,它是流读取器为它从表单中读取的每个组件调用 Loaded。这个过程(幸运的是)在表单的 AfterConstruction 之前开始,但是由该阅读器加载的每个组件都会在其加载的方法之前调用其 AfterConstruction 方法。
QED。
具有讽刺意味的是,Delphi 6 帮助文件说“在 TObject 中实现的 AfterConstruction 方法什么都不做。当创建一个在创建对象后执行某些操作的类时重写此方法。例如,TCustomForm 重写 AfterConstruction 以生成一个OnCreate 事件。”
它没有说明的是,如果你在 TCustomForm 以外的任何东西上尝试这个(它已经这样做了),它就不起作用!因为只有一个表单(已经拥有它)会在调用 AfterConstruction 之前加载它的 OnCreate 属性。任何其他组件都不会,因为表单调用的 DFM 读取器在加载之前调用 AfterConstruction! Borland 等人的一个明显案例。人。不理解他们自己的代码,或者充其量是编写一个帮助文件条目,暗示某事是可能的,而实际上并非如此。
注意,如果您的组件不在表单上并且是在运行时创建的(即使这是作为“拥有”组件),则不会调用其“Loaded”方法,因为不涉及流读取器。
另一个有趣的地方是“Dr”Bob Swart 前段时间写的关于 AfterConstruction 的内容,即它代表了可以调用虚方法的点。显然这只是部分正确:如果在 AfterConstruction 之前调用表单的 Loaded 方法,那么如果这是真的,您将无法从 Loaded 调用任何虚拟方法。情况并非如此(显然),因为 Loaded 本身就是一个虚拟方法!显然,流读取器在构造函数和 AfterConstruction 之间调用表单的 Loaded。这就引出了一个问题:流阅读器实际上是通过什么方法调用的?我的猜测是它在应用程序(而不是表单)的控制下运行,并且它故意为表单而不是其他组件调用 AfterConstruction,或者它是表单的构造函数在创建 VMT 之后所做的最后一件事,因此在表单中调用 AfterConstruction 之前发生的最后一件事。因此,在调用表单的 AfterConstruction 之前,调用表单拥有的所有 AfterConstruction-Loaded 组件对联。跟踪调用还表明,在调用所有这些组件的所有加载方法之前,大多数情况下都会为所有这些组件调用 AfterConstruction。但是,我没有测试存在分层“父级”(例如带有组件的面板)的情况,因此可能会有变化。