Xel Naga
Xel Naga

Reputation: 976

How to Detect a TPopupMenu's OnClose (OnPopDown) Event in Delphi applications

I can write some code inside TPopupMenu's OnPopUp event. But I also need another event for OnPopDown. Is there any way to do it using Delphi 10.3.3?

Upvotes: 1

Views: 918

Answers (2)

Kerem
Kerem

Reputation: 449

In newer version (e.g. 11.2 Alexandria) TPopupMenu has an build in OnClose event

Upvotes: 1

Andreas Rejbrand
Andreas Rejbrand

Reputation: 109158

There are various options you can try.

Approach 1

In the simpler case when you have a particular control whose context menu you need to track, you can handle its WM_CONTEXTMENU message manually:

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

where (for example)

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;

The test ClientRect.Contains(ScreenToClient(Message.Pos)) is necessary so that you don't "overwrite" the scrollbar's own context menu. Also, you need to consider the case when the context menu is opened using the keyboard (e.g. menu key or Shift+F10).

Approach 2

If this is not enough for you, you could create your own TPopupMenu child class and override its Popup method, which is virtual. Add a DoPopdown method and call it at the end (following the design of the DoPopup method).

To quickly test this approach, you can use an interposer class:

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

implemented as

{ TPopupMenu }

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

But of course it is nicer to create a true descendant class (TPopupMenuEx, perhaps?) that you register in the IDE. Add an FOnPopdown: TNotifyEvent private field, a DoPopdown protected function, and an OnPopdown published property. This precisely mimics the OnPopup mechanism.

Needless to say, this approach also works with a TTrayIcon's menu.

Upvotes: 6

Related Questions