这是关于Delphi和VCL.
我有几个框架可以用于多种形式,通常是在代码中创建并添加到表单中.表单可能包含其中几个框架.当包含它的表单被取消激活时,我需要在这些帧中执行一些代码,并在激活它时将其反转.
TMyFrame.FormActivated; TMyFrame.FormDeactivated
一种解决方案是在那些调用框架方法的表单中使用FormActivate / FormDeactivate事件处理程序.
procedure TMyForm.OnActivate(_Sender: TObject); begin FFrame1.FormActivated; FFrame2.FormActivated; end;
这就是我现在实现它的方式,但它有几个缺点:
>我必须在包含这些帧的实例的每个表单中实现它
>表单必须知道某些帧需要此调用(紧耦合)
>框架需要发布在这些事件中调用的两个方法.我宁愿不公开这些方法.
另一种选择是从帧的构造函数中设置FormActivate / FormDeactivate事件.但这意味着在这些事件中不能执行其他代码,如果在同一表单上有多个这样的帧,它将无法工作.
是否有任何其他选项适用于包含其中几个框架的任何表单?
如果这很重要,我需要Delphi 2007.
解决方法
(假设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;
这种方式耦合非常松散,它仍然允许您通过覆盖需要特殊处理的后代中的CM_ACTIVATE或CM_DEACTIVATE消息处理程序来覆盖默认的TMyFrame行为.
注意事项:
>这还没有经过测试 – 这只是一个快速的建议,作为一个起点.您也可以声明并使用自己的自定义消息而不是CM_ACTIVATE / CM_DEACTIVATE,以避免对VCL的其余部分造成任何干扰.> NotifyControls通知所有控件 – 不仅是帧 – 但是普通控件默认忽略/不处理CM_ACTIVATE / CM_DEACTIVATE消息,因此它应该不是问题.您还可以实现自己的NotifyFrames方法.