Delphi 扩展屏幕中所有菜单项的事件OnClick以执行另一个代码块

Delphi 扩展屏幕中所有菜单项的事件OnClick以执行另一个代码块,delphi,delphi-5,Delphi,Delphi 5,我想在屏幕上将一个事件OnClick设置为所有TMenuItems,以执行该事件当前执行的操作,并设置另外几行代码。我目前正在使用Delphi5 例如,假设我有一个带有以下代码的TMenuItem: procedure TdesktopForm.MenuFoo1Click(Sender: TObject); begin ShowMessage(TComponent(Sender).Name) end; 我还有以下程序: procedure TdesktopForm.bar; begin

我想在屏幕上将一个事件
OnClick
设置为所有
TMenuItems
,以执行该事件当前执行的操作,并设置另外几行代码。我目前正在使用Delphi5

例如,假设我有一个带有以下代码的
TMenuItem

procedure TdesktopForm.MenuFoo1Click(Sender: TObject);
begin
  ShowMessage(TComponent(Sender).Name)
end;
我还有以下程序:

procedure TdesktopForm.bar;
begin
  ShowMessage('extra')
end;
我希望每次单击TMenuItem时,程序都会显示TMenuItem的名称以及“额外”消息

所示的示例只是对我的问题的一个演示,因为在实际软件中,我有300多个菜单项,我希望一般地这样做,因此我不必向所有当前菜单单击添加额外的代码行,也不必在添加新菜单项时添加这些代码行。执行顺序(在菜单单击和额外的代码块之间)并不重要


我尝试使用
TActionList
,但无法检索触发动作的对象,因此无法打印其名称。我尝试使用
ActiveControl
,但它总是返回当前聚焦的对象,而不是我单击的实际菜单。而且,
TAction
execute事件会覆盖我的
TMainMenu。只要所有事件处理程序都是在某个时间点分配的(无论是在设计时还是在运行时),并且之后不进行更改,就可以这样做:

  • 枚举菜单中的所有菜单项
  • 对于每个对象,创建一个如下所述的对象

    type
      TEventInterceptor = class(TComponent)
      private
        FOrigEvent: TNotifyEvent;
        FAdditionalEvent: TNotifyEvent;
        procedure HandleOnClick(_Sender: TObject);
      public
        constructor Create(_MenuItem: TMenuItem; _AdditionalEvent: TNotifyEvent);
      end;
    
    constructor TEventInterceptor.Create(_MenuItem: TMenuItem; _AdditionalEvent: TNotifyEvent);
    begin
      inherited Create(_MenuItem);
      FOrigEvent := _MenuItem.OnClick;
      FAdditionalEvent := _AdditionalEvent;
      _MenuItem.OnClick := HandleOnClick;
    end;
    
    procedure TEventInterceptor.HandleOnClick(_Sender: TObject);
    begin
      FOrigEvent(_Sender);
      FAdditinalEvent(_Sender);
    end;
    
  • 请注意,此代码完全未经测试,甚至可能无法编译。 我也不确定这是否适用于Delphi5。不过Delphi6也有,所以机会很大

    编辑: 一些附加说明(感谢您的评论):

    • 从TComponent继承此类会使窗体在销毁时自动释放它
    • HandleOnClick在调用FOrigEvent之前可能会检查是否已分配FOrigEvent

    IMHO如果你真的想走这条路,战术可能是更好的选择。这里有两个地方可以处理它
    TAForm.ActionList1Execute(Action:TBasicAction;var Handled:Boolean);开始显示消息(Action.ActionComponent.Name);结束
    程序TAForm.AllActionsExecute(发送方:TObject);开始显示消息(TAction(Sender.ActionComponent.Name);结束
    我尝试使用
    ActionComponent
    ,但此属性在我的
    traction
    中不存在。我猜它是在一个比我现在使用的版本更新的版本中引入的。附加一个wm_命令处理程序,那么你就可以完全按照预期复制触发项clickWork的功能。试图使用评论中建议的wm_命令,但无法检索回句柄。感谢您为编写此片段所做的努力!作为补充说明,我删除了
    t组件
    继承,以提高内存使用率和简单性,它也起到了作用!可能会导致内存泄漏如果您的拦截器实例没有被menuitem“赢得”,它们如何被销毁在调用
    FOrigEvent
    处理程序之前,如果分配了
    (FOrigEvent)
    ,我还会放置一个
    。因为它以前可能没有分配过,否则会导致AV。“woned”->“owned”--抱歉,编辑时间到了,我会在下次发布之前进行更好的检查。但是作为
    t组件
    子组件,有一个关于隐藏
    创建
    虚拟方法的提示,由于参数列表不同,我无法覆盖它