在 Delphi 6 中为动态创建的 VCL 组件实例显式调用 Loaded 方法的替代方法?

Rob*_*ler 5 delphi vcl

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

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

War*_* P 4

如果您需要在代码中调用 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:

  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.
Run Code Online (Sandbox Code Playgroud)

在我的 TMyFractal.Change 方法中,每次在运行时、初始设置后修改任何系数 P1-P4 时,我都会调用一次昂贵的 RegenerateCurve 方法,并且在从 DFM 流入组件时调用一次,其中 Loaded 仅用于处理这样一个事实:我很难期望在我的控件中执行开始更新/结束更新,就像我在上面的代码中所做的那样。