Displaying a PopupMenu from a tray icon is a little tricky. There is actually a well-known issue in Windows itself that causes problems, and it is even documented in MSDN:
TrackPopupMenu function
To display a context menu for a notification icon, the current window must be the foreground window before the application calls TrackPopupMenu or TrackPopupMenuEx. Otherwise, the menu will not disappear when the user clicks outside of the menu or the window that created the menu (if it is visible). If the current window is a child window, you must set the (top-level) parent window as the foreground window.
However, when the current window is the foreground window, the second time this menu is displayed, it appears and then immediately disappears. To correct this, you must force a task switch to the application that called TrackPopupMenu
. This is done by posting a benign message to the window or thread, as shown in the following code sample:
SetForegroundWindow(hDlg);
// Display the menu
TrackPopupMenu( hSubMenu,
TPM_RIGHTBUTTON,
pt.x,
pt.y,
0,
hDlg,
NULL);
PostMessage(hDlg, WM_NULL, 0, 0);
To account for this in Delphi, you can set the PopupMenu.AutoPopup
property to false and then call the PopupMenu.Popup()
method when needed, eg:
procedure TForm1.FormContextPopup(Sender: TObject);
begin
ShowPopup;
end;
procedure TForm1.TrayIcon1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if Button = mbRight then ShowPopup;
end;
procedure TForm1.ShowPopup;
begin
BringToFront;
with Mouse.CursorPos do
PopupMenu1.Popup(X, Y);
PostMessage(Handle, WM_NULL, 0, 0);
end;