右键单击任何菜单项时如何获取 MenuItem 名称?

Posted

技术标签:

【中文标题】右键单击任何菜单项时如何获取 MenuItem 名称?【英文标题】:How to get the MenuItem name when right-clicking any menu item? 【发布时间】:2021-12-30 02:45:05 【问题描述】:

在 Windows 10 上的 32 位 Delphi 11 VCL 应用程序中,当右键单击任何菜单项时,我需要获取单击的 MenuItem 的名称。

我使用TApplicationEvents 组件和此代码在我单击任何菜单项时收到通知:

procedure TformMain.ApplicationEvents1Message(var Msg: tagMSG; var Handled: Boolean);
begin
  case Msg.message of
    Winapi.Messages.WM_COMMAND:
      begin
        CodeSite.Send('TformMain.ApplicationEvents1Message: WM_COMMAND');
      end;
  end;
end;

但是:

    如何仅在右键单击菜单项时获得通知?

    如何获取被点击的MenuItem的NAME?

【问题讨论】:

WM_COMMAND 在选择菜单项时发出(即左键单击)。要允许右键单击选择菜单项,必须使用 TPM_RIGHTBUTTON 标志(默认情况下不是)调用 TrackPopupMenu/Ex()。要检测菜单项上的右键单击,您必须通过使用 TPM_RECURSE 标志调用 TrackPopupMenuEx() 来显示菜单,然后将 WM_MENURBUTTONUP 消息处理到菜单的所有者窗口。 相关/欺骗:Detect left/right mouse button on menu item click? 【参考方案1】:

每个TMenu(即TMainMenuTPopupMenu)都提供了一个方法FindItem,它可以让你找到一个项目按不同的标准。在您的情况下,对表单主菜单的正确调用是

TheMenuItem := Menu.FindItem(Msg.wParam, fkCommand);

【讨论】:

感谢您的信息。但是如何获取 TMenu(即 TMainMenu 或 TPopupMenu)名称呢? @user1580348 为什么需要这个名字? MenuTForm 的属性。 @user1580348 表单本身具有分配TMainMenuTPopupMenu 的属性 - 只需尝试其中一个。否则枚举所有控件。 检测当前打开了哪个菜单(TMainMenu 或 TPopupMenu)会很有用。可以使用EnumThreadWindows 来实现吗?【参考方案2】:

由于我的应用程序中有多个表单,并且每个表单上有多个(弹出)菜单,因此这里需要一个特殊的解决方案:

procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG; var Handled: Boolean);
begin
  case Msg.message of
      Winapi.Messages.WM_COMMAND:
      begin
        // Todo: Check HERE for RightMouseButtonDown - BUT HOW? (Or how to check HERE for modifier keys?)

        var ThisMenuItem := GetMenuItem(Msg.wParam);
        if Assigned(ThisMenuItem) then
        begin
          CodeSite.Send('TForm1.ApplicationEvents1Message: Clicked MenuItem Name', ThisMenuItem.Name);
        end;

      end;
  end;
end;

function TForm1.GetMenuItem(const aWParam: NativeUInt): TMenuItem;
var
  ThisMenuItem: TMenuItem;
begin
  Result := nil;
  var ThisForm := Screen.ActiveForm; // works on any form in the application
  for var i := 0 to ThisForm.ComponentCount - 1 do
  begin
    if ThisForm.Components[i] is TMenu then
    begin
      ThisMenuItem := TMenu(ThisForm.Components[i]).FindItem(aWParam, fkCommand);
      if Assigned(ThisMenuItem) then
      begin
        Result := ThisMenuItem;
        EXIT;
      end;
    end;
  end;
end;

【讨论】:

是的:如果可以立即使用result(在函数中),为什么还要使用单独的变量? 程序员经常使用单独的变量来让非程序员更容易理解代码。 否:The myth of increased readability。写if result<> nil then exit; 会更清楚。甚至ThisMenuItem这个名字也是错误的,因为它与任何“this”都没有关系,如果不是Item,最多应该命名为FoundItem。反问:为什么不选择ThisFormMenuItem 你为什么对我的变量名感兴趣? 您的答案的早期版本包括“任何优化?”,因此是我的 cmets。此答案也仅重复 Uwe Raabe 根据您的问题已经回答的内容 - 您的后续请求不在原始问题中,但您选择了自己的“正确”。不要忽视其他人的贡献,不要忽视这是公共领域,而不是“你的”代码——现在每个人都可以使用它(就像每个人的帮助都对你可用一样)。

以上是关于右键单击任何菜单项时如何获取 MenuItem 名称?的主要内容,如果未能解决你的问题,请参考以下文章

如何获取在 NSOutlineView 的上下文菜单中右键单击的元素?

单击另一个菜单项时如何切换菜单

在java中单击菜单项时如何更改形状

单击侧菜单项时如何避免刷新页面

我们如何在单击菜单条项时突出显示活动菜单项?

如何从 XCUITest 中的 MenuItem 读取值?