代码之家  ›  专栏  ›  技术社区  ›  Gregor Brandt

Delphi中的loaded()后调用的是什么

  •  1
  • Gregor Brandt  · 技术社区  · 14 年前

    我有一些代码可以在loaded()函数中设置内部对象。但是,一些外部对象尚未完全创建,而是在loaded()函数完成之后创建的。Delphi调用loaded()后调用什么函数?

    更好的是,组件的创建顺序是什么?

    基本上我有一个TCP服务器和客户机。大多数人会将这两个组件放在两个单独的应用程序中,有些人会将它们放在同一个应用程序中以供本地访问。

    我的客户机尝试在onloaded()中从服务器获取数据,但服务器可能还没有启动!我想知道在调用了所有onloaded()之后是否调用了另一个函数。

    5 回复  |  直到 13 年前
        1
  •  3
  •   Ken White    14 年前

    加载是在DFM流入后立即调用的,不应用于访问服务器。您最好的选择可能是在构造函数中向您自己发布一条自定义消息,并拥有一个响应该消息的消息处理程序过程。发布消息会将其放入消息队列的末尾,因此在处理完前面的所有其他消息之前,不会对其进行处理。这应该会延迟足够长的时间,使您的组件能够完全构建以供使用。

        2
  •  2
  •   Francesca    14 年前

    通常情况下,您会为此而重写tobject.afterconstruction。

    执行顺序为:

      each Component.AfterConstruction in creation order
    (Form or DataModule).Loaded  
      each Component.Loaded in creation order
    (Form or DataModule).AfterConstruction 
    

    特雷斯:

    Debug Output: button AfterConstruction Process Project2.exe (4876)
    Debug Output: Form Loaded Process Project2.exe (4876)
    Debug Output: button Loaded Process Project2.exe (4876)
    Debug Output: Form AfterConstruction Process Project2.exe (4876)
    
        3
  •  2
  •   Mia Clarke    13 年前
    1. 我在一些组件中使用了断点,并牢固地确定在加载之前调用AfterConstruction,而不是在加载之后调用AfterConstruction。

    2. 我也在一张表格上做了同样的事情,并且坚定地认为,后结构是在加载后调用的,而不是以前。

    请记住,后期构造是一种tobject方法,但不加载。因此,loaded是由代码生成的,这些代码可能不一定将其相对于后构造按特定顺序排列,因为loaded实际上不是tobject的构造序列的一部分,而后构造是。

    事实上,如果您研究RTL源代码,您会发现加载的代码甚至不会被tcomponent的self.method调用,而是由正在读取dfm的流读取器调用,这很可能是在“owner”组件的控制下发生的。因此,我强烈建议其与后期施工执行的关系并不能真正得到保证。它以特定的顺序出现在表单中的事实是,表单很可能是启动流读取的组件。换言之,这是一个方便的事故,装载是在事后的形式。

    进一步的研究表明,包含以下代码的非表单组件可能永远不会调用事件处理程序。

    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流读卡器的调用程序,它是为从表单中读取的每个组件调用已加载的流读卡器。这个过程在表单的后构造之前开始(幸运的是),但是由该读卡器加载的每个组件在其加载方法之前都会调用其后构造方法。

    QED。

    具有讽刺意味的是,Delphi6帮助文件说“Tobject中实现的后构造方法什么也不做。当创建一个在创建对象后采取某些操作的类时,重写此方法。例如,tcustomform重写构造后生成onCreate事件。”

    它省略的是,如果您在除tcustomform之外的任何东西上尝试此操作(已经尝试过了),它将不起作用!因为在调用AfterConstruction之前,只有一个已经拥有它的窗体才会加载它的OnCreate属性。任何其他组件都不会,因为表单调用的DFM读卡器在加载前调用构造后调用!Borland等人的一个明确案例。不理解他们自己的代码,或者最多写一个帮助文件条目,这意味着有些事情是可能的,而事实上这是不可能的。

    注意,如果您的组件不在表单上,并且是在运行时创建的(即使它是“拥有的”组件),则不会调用它的“已加载”方法,因为不涉及流读取器。

    另一个有趣的地方是“Bob Swart博士”一段时间前写的关于后构造的东西,也就是说,它代表了可以调用虚拟方法的地方。显然,这只是部分正确的:如果在构造后调用窗体的已加载方法,那么如果为真,则无法从已加载中调用任何虚拟方法。显然,情况并非如此,因为加载本身就是一个虚拟方法!显然,为窗体加载的是由流读取器在构造函数和构造后之间调用的。它引出了一个问题:流阅读器实际上是通过什么方法被调用的?我的猜测是,它在应用程序(而不是表单)的控制下运行,并且它故意为表单调用与其他组件不同的后构造,或者它是表单的构造函数在创建了vmt之后所做的最后一件事,因此在for中调用后构造之前发生的最后一件事。m.因此,在调用窗体的后构造之前,调用窗体所拥有的所有组件的后构造加载的联。跟踪调用还表明,在调用所有已加载的方法之前,大多数组件都是在构造后调用的。但是,我没有测试有层次“父级”的情况(例如面板上有组件),因此可能会有变化。

        4
  •  1
  •   jachguate    14 年前

    我不知道你说的是什么意思

    服务器可能尚未启动

    不管怎样,如果客户机和服务器都在同一个应用程序表单或数据模块上,我会看到替代方案:

    1. 您可以“强制”系统创建服务器 之前 客户端和 上服务器 在服务器的onload中,它将 向上的 在客户端上加载,因为 documentation 说:

      当流系统从表单文件加载表单或数据模块时,它首先通过调用表单组件的构造函数构造表单组件,然后从表单文件读取其属性值。读取所有组件的所有属性值后, 流系统按照组件的创建顺序调用每个组件的已加载方法。 . 这使组件有机会初始化任何依赖于其他组件或其其他部分的值的数据。

    2. 每当服务器启动时,通知“客户机”让其初始化(从服务器中提取数据)。您可以使用直接方法调用、发布消息或任何您觉得满意的方法。

    3. 让客户 站起来 它内部的服务器是自己的onload方法。

        5
  •  1
  •   iamjoosy    14 年前

    为什么不使用主窗体的onCreate事件?