这是关于德尔福和VCL。
我有几个可以在多种形式中使用的框架,通常是在代码中创建并添加到表单中。表单可能包含其中几个框架。当包含它的表单被取消激活时,我需要在这些帧中执行一些代码,并在激活它时将其反转。
TMyFrame.FormActivated;
TMyFrame.FormDeactivated
一种解决方案是在那些调用框架方法的表单中使用FormActivate / FormDeactivate事件处理程序。
procedure TMyForm.OnActivate(_Sender: TObject);
begin
FFrame1.FormActivated;
FFrame2.FormActivated;
end;
这就是我现在实现它的方式,但这有几个缺点:
另一种选择是在框架的构造函数中设置FormActivate / FormDeactivate事件。但这意味着在这些事件中不能执行其他代码,如果在同一表单上有多个这样的帧,它将无法工作。
是否有任何其他选项适用于包含多个这些帧的任何表单?
如果这很重要,我需要Delphi 2007。
答案 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;
这种耦合非常松散,它仍然允许您通过覆盖需要特殊处理的后代中的TMyFrame
或CM_ACTIVATE
消息处理程序来覆盖默认的CM_DEACTIVATE
行为。
注意事项:
CM_ACTIVATE
/ CM_DEACTIVATE
,以避免干扰VCL的其余部分。NotifyControls
通知所有控件 - 不仅是帧 - 而是普通控件默认忽略/不处理CM_ACTIVATE
/ CM_DEACTIVATE
消息,所以它不应该'是个问题。您还可以实现自己的NotifyFrames
方法。答案 1 :(得分:6)
不知道这是否可行,但几年前我遇到了类似的问题,并通过某种形式/帧继承来解决它。有一个基本框架类声明这些方法虚拟和一个表单类捕获事件并迭代调用适当的框架方法的所有子框架。派生的帧根据需要覆盖这些方法。这减少了与基类的耦合。
在后来的重构中,这被改为框架实现的接口,完全消除了窗体和框架类之间的耦合。