Delphi 应用程序中TPopupMenu的OnClose(OnPopDown)事件检测

gmol1639  于 2023-03-12  发布在  其他
关注(0)|答案(2)|浏览(203)

我可以在TPopupMenu的OnPopUp事件里面写一些代码。但是我还需要另一个OnPopDown事件。有没有办法用 Delphi 10.3.3来做呢?

2w3rbyxf

2w3rbyxf1#

您可以尝试各种选项。

方法1

在更简单的情况下,当您需要跟踪特定控件的上下文菜单时,可以手动处理其WM_CONTEXTMENU消息:

protected
    procedure WMContextMenu(var Message: TWMContextMenu);
      message WM_CONTEXTMENU;

其中(例如)

procedure TForm1.WMContextMenu(var Message: TWMContextMenu);
begin
  if
    Assigned(PopupMenu)
      and
    (ClientRect.Contains(ScreenToClient(Message.Pos)) or (Message.Pos = Point(-1, -1)))
  then
  begin
    Windows.Beep(200, 500); // pre-popup code
    if (Message.XPos = -1) and (Message.YPos = -1) then // Menu key or Shift+F10
      with ClientToScreen(Point(0, 0)) do
        PopupMenu.Popup(X, Y)
    else
      PopupMenu.Popup(Message.XPos, Message.YPos);
    Windows.Beep(400, 500); // post-popup code
  end
  else
    inherited;
end;

测试ClientRect.Contains(ScreenToClient(Message.Pos))是必要的,这样你就不会“覆盖”滚动条自己的上下文菜单。另外,你需要考虑上下文菜单是使用键盘打开的情况(例如,菜单键或Shift+F10)。

方法2

如果这对您来说还不够,您可以创建自己的TPopupMenu子类并覆盖其Popup方法,该方法是虚拟的。添加一个DoPopdown方法并在最后调用它(遵循DoPopup方法的设计)。
要快速测试这种方法,可以使用interposer类:

type
  TPopupMenu = class(Vcl.Menus.TPopupMenu)
    procedure Popup(X, Y: Integer); override;
  end;

实施为

{ TPopupMenu }

procedure TPopupMenu.Popup(X, Y: Integer);
begin
  inherited;
  Windows.Beep(400, 500); // post-popup code
end;

当然,最好创建一个真正的子类(TPopupMenuEx)并在IDE中注册,添加一个FOnPopdown: TNotifyEvent私有字段、一个DoPopdown受保护函数和一个OnPopdown发布属性,这样可以精确地模拟OnPopup机制。
不用说,这种方法也适用于TTrayIcon的菜单。

klr1opcd

klr1opcd2#

在较新版本(例如11.2 Alexandria)中,TPopupMenu具有内置OnClose事件

相关问题