Delphi 10,柏林,弹出菜单和隐藏显示

Delphi 10, Berlin, popup menu and hide-show

在窗体上,我有 TrayIcon 和 PopupMenu 组件。

当我运行项目时,表格显示正常。右击窗体,出现弹出菜单。

在 TrayIcon 上,左键单击显示 Form ok。

在 TrayIcon 上,右键单击显示 PopupMenu。 Select "SHOW"项,表格显示正常

但是,在此之后,PopupMenu 不再启用。右击无效!

我在尝试你所做的时遇到了同样的问题,似乎当你隐藏表单时 form.popupmenu 的值变为 nil,我的解决方案是添加另一个具有相同事件处理程序的弹出菜单,分配第一个到表单,第二个到托盘图标,它将起作用。

编辑

Sertac Akyuz 感谢您的说明 隐藏表单时 Popupmenu.AutoPopup 变为 false 而不是 form.popupmenu 变为 nil

我观察到 PopUpMenu 的 "AutoPopup" 属性 在 show 事件中是错误的;将其设置回恢复预期的行为:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Menus, Vcl.ExtCtrls;

type
  TForm1 = class(TForm)
    PopupMenu1: TPopupMenu;
    Show1: TMenuItem;
    Hide1: TMenuItem;
    TrayIcon1: TTrayIcon;
    procedure Show1Click(Sender: TObject);
    procedure Hide1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Hide1Click(Sender: TObject);

begin
   Hide;
   TrayIcon1.Visible := true;
end;

procedure TForm1.Show1Click(Sender: TObject);

begin
   ///////////////////
   //
   // Comment out this line and app will have OP's observed behavior
   Popupmenu.AutoPopup := true;
   ///////////////////

   Show;
end;

end.

从托盘图标显示 PopupMenu 有点棘手。 Windows 本身就有一个众所周知的问题导致问题,甚至在 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);

为了在 Delphi 中解决这个问题,您可以将 PopupMenu.AutoPopup 属性 设置为 false,然后在需要时调用 PopupMenu.Popup() 方法,例如:

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;