当拥有它的表单被激活/停用时,是否有一种简单的方法可以在框架中调用方法?

Is there an easy way to call a method in a frame, when the form that owns it gets activated / deactivated?

这是关于 Delphi 和 VCL。

我有几个可用于多种形式的框架,通常在代码中创建并添加到形式中。一个表单可能包含多个这样的框架。当包含它的表单被停用时,我需要在这些框架中执行一些代码,并在它被激活时反转它。

TMyFrame.FormActivated;
TMyFrame.FormDeactivated

一种解决方案是在那些调用框架方法的表单中使用 FormActivate / FormDeactivate 事件处理程序。

procedure TMyForm.OnActivate(_Sender: TObject);
begin
  FFrame1.FormActivated;
  FFrame2.FormActivated;
end;

这就是我目前的实现方式,但有几个缺点:

另一种选择是在框架的构造函数中设置 FormActivate / FormDeactivate 事件。但这将意味着在这些事件中无法执行其他代码,并且如果在同一表单上有多个这样的框架,它将无法工作。

是否有任何其他选项适用于包含多个这些框架的任何表单?

如果这很重要,我需要 Delphi 2007 年的这个。

不知道这在这里是否可行,但几年前我遇到过类似的问题并通过某种 form/frame 继承解决了它。有一个基本框架 class 声明这些方法是虚拟的,还有一个形式 class 捕获事件并遍历所有调用适当框架方法的子框架。派生框架根据需要覆盖这些方法。这减少了与基础 classes.

的耦合

在后来的重构中,这被更改为由框架实现的接口,完全消除了表单和框架之间的耦合 classes。

(假设 VCL)框架应该以某种方式拦截父窗体的 activate/deactivate 事件。有很多可能的方法可以做到这一点(设置父表单的 OnActivate/OnDeactivate 事件,使用 SetWindowLong(GWL_WNDPROC) or WindowProc 进行子类化)但是如果多个框架实例对同一个执行此操作,则必须强制执行例如,取下挂钩的顺序必须与插入挂钩的顺序相反。此外,当 window 句柄被重新创建时,您会遇到正确处理情况的问题。

一个更简单的方法可能是使用类似这样的东西作为项目中所有表单的祖先:

TMyForm = class(TForm)
  procedure Activate; override;
  procedure Deactivate; override;
end;

procedure TMyForm.Activate;
begin
  inherited Activate;
  NotifyControls(CM_ACTIVATE);
end;

procedure TMyForm.Deactivate;
begin
  inherited Deactivate;
  NotifyControls(CM_DEACTIVATE);
end;

以及类似这样的东西作为项目中所有框架的祖先:

TMyFrame = class(TFrame)
  procedure CMActivate(var Msg: TCMActivate); message CM_ACTIVATE;
  procedure CMDeactivate(var Msg: TCMDeactivate); message CM_DEACTIVATE;
end;

procedure TMyFrame.CMActivate(var Msg: TCMActivate);
begin
  // parent form activated
end;

procedure TMyFrame.CMDeactivate(var Msg: TCMDeactivate);
begin
  // parent form deactivated
end;

这种耦合非常松散,它仍然允许您通过覆盖需要特殊处理的后代中的 CM_ACTIVATECM_DEACTIVATE 消息处理程序来覆盖默认的 TMyFrame 行为。

注意事项:

  1. 这还没有经过测试 - 这只是一个快速的建议,作为一个起点。您还可以声明并使用自己的自定义消息而不是 CM_ACTIVATE/CM_DEACTIVATE,以避免对 VCL 的其余部分造成任何干扰。
  2. NotifyControls 通知 所有 控件 - 不仅是帧 - 但普通控件 ignore/don 不处理 CM_ACTIVATE/CM_DEACTIVATE默认情况下是消息,所以这应该不是问题。您还可以实现自己的 NotifyFrames 方法。