Delphi中Loaded()之后调用了什么
我有一些代码在 Loaded() 函数中对内部对象进行一些设置。但是,某些外部对象尚未完全创建,而是在 Loaded() 函数完成之后创建。 Delphi调用Loaded()后调用了什么函数?
更好的是组件的创建顺序是什么?
基本上我有一个 TCP 服务器和客户端。大多数人会将这两个组件放置到两个单独的应用程序中,有些人会将它们放置在同一个应用程序中以进行本地访问。
我的客户端尝试在 OnLoaded() 中从服务器获取数据,但服务器可能尚未启动!我想知道在调用所有 OnLoaded() 之后是否调用了另一个函数。
I have some code that does some setup of internal objects in the Loaded() function. However, some external objects are not completely created yet, but are AFTER the Loaded() function is complete. What function does Delphi call after it calls Loaded()?
Better yet what is the creation sequence of a component?
Basically I have a TCP Server and Client. Most people will place those two components into two separate applications, some will place them in the same application for local access.
My Client tries to fetch data from the server in OnLoaded(), but the server may not be up yet! I want to know if another function is called after all the OnLoaded()'s are called.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
Loaded 在 dfm 流入后立即调用,并且不应该用于访问服务器。您最好的选择可能是在构造函数中向自己发布一条自定义消息,并有一个响应该消息的消息处理程序过程。发布消息会将其放入消息队列的末尾,因此在处理完其前面的所有其他消息之前,不会对其进行处理。这应该会延迟足够长的时间,以便您的组件完全构建起来可供使用。
Loaded is called immediately after the dfm is streamed in, and shouldn't be used to access the server. Your best bet is probably to post a custom message to yourself in the constructor, and have a message handler procedure that responds to that message. Posting the message puts it into the end of the message queue, and therefore it won't get processed until all the other messages ahead of it has been handled. This should delay things long enough for your components to be fully constructed for use.
我在某些组件中使用了断点,并坚定地认为 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 之前,这有点巧合。
进一步的研究表明,包含以下代码的非形式组件可能永远不会调用事件处理程序。
原因是AfterConstruction,如果在属性加载之前调用,会发现FOnCreate还没有被赋值!
在这种情况下,您确实必须使用以下内容:
就像我所说的,这将为表单拥有的组件产生与表单本身不同的结果! TForm 组件通常是 DFM 流读取器的调用者,并且流读取器为从表单读取的每个组件调用 Loaded。 (幸运的是)这个过程在表单的 AfterConstruction 之前启动,但是该读取器加载的每个组件都会在其加载的方法之前调用其 AfterConstruction 方法。
量子ED。
具有讽刺意味的是,Delphi 6 帮助文件中说“TObject 中实现的 AfterConstruction 方法什么都不做。在创建一个在创建对象后执行某些操作的类时重写此方法。例如,TCustomForm 重写 AfterConstruction 以生成 OnCreate 事件。 ”
它没有说的是,如果您在 TCustomForm 以外的任何东西上尝试这个(它已经做到了),它就不起作用!因为只有表单(已经拥有它)才会在调用 AfterConstruction 之前加载其 OnCreate 属性。任何其他组件都不会,因为表单调用的 DFM 读取器会在 Loaded 之前调用 AfterConstruction! Borland 等人的一个明显案例。等人。不理解他们自己的代码,或者最多编写一个帮助文件条目来暗示某些事情是可能的,而实际上它是不可能的。
请注意,如果您的组件不在表单上并且是在运行时创建的(即使这是作为“拥有的”组件),则不会调用其“Loaded”方法,因为不涉及流读取器。
另一个有趣的地方是“Dr”Bob Swart 不久前写的关于 AfterConstruction 的内容,即它代表了可以调用虚拟方法的点。显然这只是部分正确:如果在 AfterConstruction 之前调用表单的 Loaded 方法,那么您将无法从 Loaded 调用任何虚拟方法(如果这是真的)。 (显然)情况并非如此,因为 Loaded 本身就是一个虚拟方法!显然,流读取器在构造函数和 AfterConstruction 之间调用了表单的 Loaded。这就引出了一个问题:流读取器实际上是通过什么方法调用的?我的猜测是,要么它在应用程序(而不是表单)的控制下运行,并且它故意以不同于其他组件的方式对表单调用 AfterConstruction,要么它是表单构造函数在创建 VMT 后执行的最后一件事,因此在表单中调用 AfterConstruction 之前发生的最后一件事。因此,在调用表单的 AfterConstruction 之前,将调用该表单所拥有的组件的所有 AfterConstruction-Loaded 对联。跟踪调用还表明,在调用所有这些组件的所有加载方法之前,大多数情况下都会调用 AfterConstruction。然而,我没有测试存在分层“父级”(例如带有组件的面板)的情况,因此可能会有所不同。
I've used breakpoints in some components and firmly established that AFTERCONSTRUCTION is called BEFORE LOADED not AFTER.
I've also done the same thing on a FORM and firmly established that AFTERCONSTRUCTION is called AFTER LOADED not BEFORE.
Bear in mind that AfterConstruction is a method in TObject, but Loaded is not. It follows that Loaded is generated by code that may not necessarily put it in a specific order relative to AfterConstruction, since Loaded is not actually part of the construction sequence of a TObject and AfterConstruction is.
Indeed, if you study the RTL source, you will see that Loaded is not even invoked by any self.method of a TComponent, but is in fact invoked by a stream reader that is reading the DFM, and that will most probably be happening under the control of an "owner" component. I strongly suggest therefore that its relationship relative to the execution of AfterConstruction is not really guaranteed. The fact that it appears in a particular order for a form is because the form is most likely the component to initiate stream reading. In other words, it smacks of a convenient accident that Loaded is before AfterConstruction in a form.
Further research shows that NON-FORM components that include the following code may never call the event handler.
The reason is that AfterConstruction, if invoked before properties are loaded, will find FOnCreate has not been assigned yet!
In such cases, you really HAVE to use the following:
Like I said, this will produce different outcomes for a component owned by a form than it would for the form itself! The TForm component is usually the invoker of the DFM stream reader and it is the stream reader that calls Loaded for each component it reads from the form. This process starts (fortunately) BEFORE the form's AfterConstruction, but each component that is loaded by that reader gets its AfterConstruction method called BEFORE its loaded method.
QED.
The great irony is that the Delphi 6 help file says "The AfterConstruction method implemented in TObject does nothing. Override this method when creating a class that takes some action after the object is created. For example, TCustomForm overrides AfterConstruction to generate an OnCreate event."
What it omits to say is that if you try this on anything other than a TCustomForm (which does it already), it doesn't work! Because only a form (which has it already) will load its OnCreate property before calling AfterConstruction. Any other component won't, because the DFM reader invoked by the form calls AfterConstruction before Loaded! A clear case of Borland et. al. not understanding their own code, or at best, writing a help file entry that implies something is possible when in fact it is not.
Note, if your component is not on a form and is created at runtime (even if this is as an "owned" component), its "Loaded" method will NOT be called, because there was no stream reader involved.
Another point of interest is something that "Dr" Bob Swart wrote some time ago about AfterConstruction, namely that it represents the point where virtual methods can be invoked. Evidently this is only partly true: if a form's Loaded method is invoked BEFORE AfterConstruction, then you would not be able to invoke any virtual methods from Loaded if that were true. This is not the case (obviously) because Loaded is itself a virtual method! Evidently, Loaded for a form is called between the constructor and AfterConstruction by the stream reader. It begs the question: by what method is the stream reader actually invoked? My guess is either that it runs under control of the application (not the form) and that it deliberately invokes AfterConstruction differently for a form than for other components, OR that it is the last thing the form's constructor does after having created the VMT and hence the last thing that occurs before AfterConstruction is called in the form. Accordingly all the AfterConstruction-Loaded couplets of components owned by the form are called before the form's AfterConstruction is called. Tracing the calls also shows that mostly AfterConstruction is called for ALL of those components before ALL of their loaded methods are called. I didn't however test the case where there are hierarchical "parents" (such as panels with components on them), so there may be variations on this.
通常您会为此目的重写 TObject.AfterConstruction。
执行顺序为:
跟踪:
Normally you would override TObject.AfterConstruction for that purpose.
The order of execution is:
Trace:
我不确定你的意思
无论如何,如果客户端和服务器都在同一个应用程序表单或数据模块上,我看到替代方案:
您可以“强制”系统之前创建服务器 在服务器的 OnLoad 中启动服务器,并且在客户端 OnLoad 中启动,因为 文档 说:
<块引用>
当流系统从表单文件加载表单或数据模块时,它首先通过调用其构造函数来构造表单组件,然后从表单文件中读取其属性值。读取所有组件的所有属性值后,流系统按照组件创建的顺序调用每个组件的 Loaded 方法。这使组件有机会初始化依赖于其他组件或其自身其他部分的值的任何数据。
每当服务器启动时通知“客户端”以使其初始化(从服务器提取数据)。您可以使用直接方法调用、发布消息或任何您觉得舒服的方式。
让客户端在其自己的 OnLoad 方法内站立服务器。
I'm not sure what you mean with
Anyway, if the client and the server are both on the same application form or datamodule, I see alternatives:
You may "force" the system to create the server before the client and up the server in the server's OnLoad and it will be up at the client OnLoad, because documentation says:
Inform the "client" whenever the server is UP to let it initialize (pull data from the server). You can use a direct method call, post a message or whatever you feel comfortable with.
Let the client stand up the server inside it's own OnLoad method.
为什么不使用主 Form 的 onCreate 事件?
Why not use the onCreate event of the main Form ?