在 Delphi 6 中为动态创建的 VCL 组件实例显式调用 Loaded 方法的替代方法?
我有几个自定义 VCL 组件,它们在重写 TComponent Loaded() 方法时执行重要任务。这在动态创建实例时会产生麻烦,因为 Delphi 全局加载器在运行时不会调用 Loaded() 方法,就像设计时放置在窗体/框架上的组件一样。我还必须将 Loaded 覆盖放在类声明的 public 部分中,以便创建组件实例的任何代码都可以调用它。最后,我必须记住为动态创建的实例调用 Loaded() ,否则微妙的错误会渗透到应用程序中,这个问题已经困扰我好几次了。
对此有更好的解决方案或方法吗?
I have several custom VCL components that do important tasks in their override of the TComponent Loaded() method. This creates a nuisance when creating instances dynamically since the Loaded() method is not called by the Delphi global loader during run-time, like it does for components that were placed on forms/frames at design-time. I also have to place the Loaded override in the public section of the class declaration so whatever code that creates an instance of the component can call it. Finally I have to remember to call Loaded() for dynamically created instances or subtle bugs will creep into the application, a problem that has bit me several times already.
Is there a better solution or approach to this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
如果您需要在代码中调用 Loaded,那么您就做错了。如果您依赖第三方控件,那么我会修复该人的控件。请参阅下文了解具体方法。
让我举一个假设的例子:假设我有 5 个已发布的属性,一旦它们全部加载,就可以生成一条复杂的曲线,甚至更好,生成一个分形,这需要很长时间。
在设计时,我想在加载后立即预览该曲线,但我不希望在 DFM 流期间重新计算该曲线 5 次,因为每个参数 P1 到 P5(Double 类型)都有一个 SetP1 方法,该方法调用受保护的方法称为 Changed,并重建我的曲线。相反,如果 csDesigning 或 csLoading 处于组件状态,则返回 SetP1 方法,然后从 Loaded 调用 Changed 一次。显然,在所有情况下,我不能单独依赖属性设置器方法来调用所有更改。因此,我需要 Loaded 告诉我做第一代一些昂贵的工作,我希望准确地完成 1 次,而不是 N 次,其中 N 是已加载的 DFM 属性的数量,这些属性具有方法集过程调用名为 Changed 或类似名称的方法。
就您而言,在运行时,您根本不应该依赖于 Loaded 被调用。相反,您应该让属性设置方法调用 Changed。如果您需要某种方法一次更改多个属性,然后只执行一次昂贵的操作,那么请实现 TMyComponent.BeginUpdate/TMyComponent.EndUpdate 类型的方法调用,并避免额外的工作。
我想不出从 Loaded 中执行某些操作有任何意义的有用地方,除了上面的情况,这些情况应该特定于设计时和基于 DFM 的类使用。我希望正确设计的 TComponent 或 TControl 仅通过在代码中创建并设置其属性来正确初始化自身。
因此,对于我假设的 TMyFractal 组件,我会在代码中创建它时执行此操作,而无需使用 DFM 加载或调用 Loaded:
在我的 TMyFractal.Change 方法中,我将调用一次昂贵的 RegenerateCurve 方法,每次任何系数 P1- P4 在运行时、初始设置后以及组件从 DFM 流入时修改一次,其中 Loaded 仅用于处理这样的事实:我很难期望做一个beginupdate/endupdate 在我的控制中,就像我在上面的代码中所做的那样。
If you need to call Loaded in your code you're doing it wrong. If you depend on a third party control that does, then I would fix that person's control. See below for how.
Let me make up a hypothetical example: Suppose I had 5 published properties, which once they are all loaded, can generate a complex curve or even better, generate a fractal, something that takes a long time.
At designtime I want to preview this curve, as soon as it's loaded, but I don't want the curve to be recalculated 5 times during DFM streaming, because each parameter P1 through P5 (type Double) has a SetP1 method, which invokes a protected method called Changed, and rebuilds my curve. Instead I have the SetP1 method return if csDesigning or csLoading are in the component states, and I then invoke Changed once, from Loaded. Clearly I can't rely on property setter methods alone, in all cases, to invoke all changes. So I need Loaded to tell me to do my first generation of some expensive work, that I want to be done 1 time exactly, not N times, where N is the number of DFM properties that would have been loaded that had method set procedures that invoked a method named Changed or something like that.
In your case, at runtime, you should not be relying on Loaded getting invoked at all. You should be instead, having your property set methods call Changed. If you need some way to change multiple properties at once, and then do some expensive thing only once, then implement a TMyComponent.BeginUpdate/TMyComponent.EndUpdate type of method call, and avoid extra work.
I can think of NO useful places where doing something from Loaded makes any sense, except for cases like the ones above, which should be specific to designtime and DFM based class use. I would expect a properly designed TComponent or TControl to properly initialize itself merely by being created in code, and by having its properties set.
So for my hypothetical TMyFractal component, I would do this when creating it in code without it ever having used DFM loading, or invoking Loaded:
In my TMyFractal.Change method, I would invoke the expensive RegenerateCurve method once, each time any coefficient P1-P4 is modified at runtime, after initial setup, and once exactly when the component is streamed in from DFM, where Loaded is only used to handle the fact that I can hardly expect to do a beginupdate/endupdate in my control like I would have done in the code above.