对于Delphi6中动态创建的VCL组件实例,是否可以显式调用加载的方法?

对于Delphi6中动态创建的VCL组件实例,是否可以显式调用加载的方法?,delphi,vcl,Delphi,Vcl,我有几个自定义VCL组件,它们在重写TComponent load()方法时执行重要任务。这在动态创建实例时会造成麻烦,因为在运行时Delphi全局加载器不会调用Loaded()方法,就像在设计时放置在表单/框架上的组件那样。我还必须将加载的覆盖放在类声明的公共部分,以便创建组件实例的任何代码都可以调用它。最后,我必须记住为动态创建的实例调用Loaded(),否则会有一些微妙的错误潜入应用程序,这个问题已经困扰了我好几次了 有更好的解决方案或方法吗?如果您需要在代码中调用Loaded,那么您就做

我有几个自定义VCL组件,它们在重写TComponent load()方法时执行重要任务。这在动态创建实例时会造成麻烦,因为在运行时Delphi全局加载器不会调用Loaded()方法,就像在设计时放置在表单/框架上的组件那样。我还必须将加载的覆盖放在类声明的公共部分,以便创建组件实例的任何代码都可以调用它。最后,我必须记住为动态创建的实例调用Loaded(),否则会有一些微妙的错误潜入应用程序,这个问题已经困扰了我好几次了


有更好的解决方案或方法吗?

如果您需要在代码中调用Loaded,那么您就做错了。如果您依赖于第三方控件,那么我将修复此人的控件。请参见下面的方法

让我来做一个假设的例子:假设我有5个已发布的属性,一旦它们全部加载,就可以生成复杂的曲线,甚至更好,生成分形,这需要很长时间

在设计时,我希望在加载该曲线后立即预览该曲线,但我不希望在DFM流期间重新计算该曲线5次,因为每个参数P1到P5(类型Double)都有一个SetP1方法,该方法调用一个名为Changed的受保护方法,并重建我的曲线。相反,如果csDesigning或csLoading处于组件状态,我将返回SetP1方法,然后从Loaded调用Changed一次。显然,在所有情况下,我不能仅仅依靠属性设置器方法来调用所有更改。因此,我需要加载来告诉我要做一些昂贵的第一代工作,我希望精确地完成1次,而不是N次,其中N是如果方法集过程调用了名为Changed的方法或类似的方法,那么将加载的DFM属性的数量

在您的情况下,在运行时,您根本不应该依赖于调用Loaded。相反,您应该更改属性集方法调用。如果您需要某种方法一次更改多个属性,然后只执行一次代价高昂的操作,那么实现TMyComponent.BeginUpdate/TMyComponent.EndUpdate类型的方法调用,并避免额外的工作

我想不出任何有用的地方,从Loaded中执行某些操作是有意义的,除了上面的情况,这些情况应该是特定于designtime和基于DFM的类使用的。我希望一个设计合理的TComponent或TControl只需在代码中创建并设置其属性,就能正确地初始化自己

因此,对于我假设的TMyFractal组件,我在代码中创建它时会这样做,而它从未使用过DFM加载或调用Loaded:

  cs := TMyFractal.Create(Self);
  cs.Parent := Self; {Parent to a form}
  cs.Align := alClient;
  cs.BeginUpdate;
  cs.P1 := 1.03;  // does NOT trigger Regenerate
  cs.P2 := 2.3;
  cs.P3 := 2.4;
  cs.P4 := 2.5;
  cs.EndUpdate; // triggers expensive Regenerate method .
  cs.Show; 

  // later someone wants to tweak only one parameter and I don't want to make them
  // call regenerate:
  cs.P5 := 3.0; // Each param change regenerates the whole curve when not loading or in a beginupdate block.

在我的TMyFractal.Change方法中,我会调用一次曲线方法,每次在运行时、初始设置后修改任何系数P1-P4时,以及在组件从DFM流入时调用一次,where Loaded仅用于处理这样一个事实,即我很难像在上面的代码中那样在控件中执行beginupdate/endupdate。

如果您不需要等待属性流式导入,则可以覆盖AfterConstruction。如果您确实需要等待,直到属性流传输进来,那么您将不得不像当前一样手动执行。因为否则组件无法知道您已经在运行时代码中完成了属性的分配。我认为您误解了加载
的目的。它在组件从.dfm流式导入后立即调用;它与运行时或设计时无关。(注意,它与在运行时设置属性无关,因为这不是它应该做的。)它对在设计时丢弃在窗体上的控件/帧起作用的原因是它们在流处理过程中存在(它们“加载”时在.dfm中)在我能想象到的任何情况下,你都不应该自己打
Loaded
。@remy是的,我想我已经说过了that@David,在对属性进行流式传输后要运行的正确机制是加载
。Robert所说的不是流式传输之后,而是在运行时手动构建之后。(很抱歉编辑太晚了-我点击Save,然后重新阅读您所写的内容。)正确的解决方案,IMO,就是您所说的-一个单独的方法,可以在您被覆盖的
加载的
结束时调用,也可以在运行时创建并设置任何必要的属性后调用。@KenWhite Robert并不是说要在那里编写代码。他所说的组件(编写器)愚蠢地认为每个人总是在表单/数据模块上使用自己的控件,并在加载中执行不应该在那里执行的操作。他想知道当在运行时实例化这些控件(而不是在设计时将其加载)时如何解决这个问题,而不必明确地调用Loaded。事实上,他正试图实现你所倡导的目标。