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

时间:2016-06-03 12:14:20

标签: delphi delphi-2007

这是关于德尔福和VCL。

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

TMyFrame.FormActivated;
TMyFrame.FormDeactivated

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

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

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

  • 我必须在包含这些框架实例的每个表单中实现它
  • 表单必须知道某些帧需要此调用(紧耦合)
  • 框架需要发布在这些事件中调用的两个方法。我宁愿不公开这些方法。

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

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

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

2 个答案:

答案 0 :(得分:7)

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

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

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;

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

注意事项:

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

答案 1 :(得分:6)

不知道这是否可行,但几年前我遇到了类似的问题,并通过某种形式/帧继承来解决它。有一个基本框架类声明这些方法虚拟和一个表单类捕获事件并迭代调用适当的框架方法的所有子框架。派生的帧根据需要覆盖这些方法。这减少了与基类的耦合。

在后来的重构中,这被改为框架实现的接口,完全消除了窗体和框架类之间的耦合。