关闭TPopupMenu时移出它-删除其浮动行为时,点击一个(总是在顶部)应用程序的外部



我的应用程序是showontop类型的窗口,弹出菜单(主菜单)在光标位置意味着在主表单(demoForm)之外,由外部winapi消息(剪贴板更改)触发。

恼人的问题是,当在应用程序外单击菜单时,菜单不会消失,而不是像通常那样单击任何菜单项或主表单来关闭菜单。焦点消失了,我的应用程序保持在顶部,菜单仍然是浮动的。

尝试遵循许多文章,甚至从D7更改到XE5都没有成功。检查了这个也:自动隐藏或关闭弹出菜单时,鼠标指针是在它-德尔福地雷是不复杂的延迟定时器或托盘控制。

具体来说,我借鉴了一个解决方案,我这样做了:

procedure TDemoForm.tmrMenumouseOutMonitorTimer(Sender: TObject);
var
  hPopupWnd: HWND;
  R: TRect;
  PT: TPoint;
begin
   hPopupWnd :=  FindWindow('#32768', mastermenu);
  if hPopupWnd = 0 then Exit;
  GetWindowRect(hPopupWnd, R);
  GetCursorPos(Pt);
  if PtInRect(R, Pt) then begin
  //do something
  end else begin
  //do something
  end;
end;

我试图用计时器(MenumouseOutMonitorTimer)轮询光标位置,以检测光标是否移出菜单(主菜单)。如果它移出,我将发出。closemenu ()

但是,这段代码抛出- string, pAnsiChar/pwidestring不匹配在D7/XE5在FindWindow()最后一个参数。也许我应该使用findwindow ?XE5直接从TPopupMenu返回一些句柄,但我不知道如何使用它们来解决我的问题。

(在Win7上,也针对XP)

我是一个完全的初学者,任何帮助将不胜感激。

完整代码在这里:

unit FmDemo;
interface
uses
  System.Classes,
  Vcl.Controls,
  Vcl.StdCtrls,
  Vcl.Forms, Menus, Dialogs, FileCtrl, ExtCtrls,PJCBView;// ....;
type
  TDemoForm = class(TForm)
    //......
    PJCBViewer1: TPJCBViewer; //custom control
    masterMenu: TPopupMenu;
    tmrMenumouseOutMonitor: TTimer;
    procedure tmrMenumouseOutMonitorTimer(Sender: TObject);
  private
    //........
    procedure menuItemClickHandler(Sender: TObject);
  end;
var
  DemoForm: TDemoForm;
implementation
uses
      Jpeg, Shellapi, Graphics, SysUtils, RichEdit, Messages;//GifImage
{$R *.dfm}
procedure tdemoform.menuItemClickHandler(Sender: TObject);
begin
  //.......
end;
procedure TDemoForm.PJCBViewer1ClipboardChanged(Sender: TObject);
var
   pnt: TPoint;
begin
  demoform.BringToFront; //formStyle -> fsStayOnTop already
  ///////////////////////////////////
  ///menu under cursor display code//
  ///////////////////////////////////
  if GetCursorPos(pnt) then
   begin
      masterMenu.Popup(pnt.X, pnt.Y);
   end;
  //remember to return focus to source window after each menu action (not implemented)
end;
procedure TDemoForm.tmrMenumouseOutMonitorTimer(Sender: TObject);
var
  hPopupWnd: HWND;
  R: TRect;
  PT: TPoint;
begin
  hPopupWnd :=  FindWindow('#32768', masterMenu);
  if hPopupWnd = 0 then Exit;
  GetWindowRect(hPopupWnd, R);
  GetCursorPos(Pt);
  if PtInRect(R, Pt) then begin
  //do something
  end else begin
  //do something
  end;
end;
//... other business logic
initialization
  CF_RTF := RegisterClipboardFormat( richedit.CF_RTF );
end.

这是一个不需要第三方控制的MCVE。

...
implementation
uses
  menus;
{$R *.dfm}
var
  Pop: TPopupMenu;
  Wnd: HWND;
procedure TForm1.FormCreate(Sender: TObject);
begin
  Left := 200;
  Top := 100;
  Pop := TPopupMenu.Create(nil);
  Pop.Items.Add(TMenuItem.Create(Pop));
  Pop.Items[0].Caption := 'test';
  Wnd := GetForegroundWindow;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
  SetForegroundWindow(Wnd); // comment this for the popup to be released when clicked outside
  Pop.Popup(100, 50);
end;

在表单外点击,弹出窗口将不会被释放。

正如你所看到的,我不得不人为地强加重现这个问题的条件,即当你弹出菜单时,你的窗口不在前台。

正如在你链接的页面的几个地方提到的,为了正常释放弹出窗口,当你弹出菜单时,你的窗口必须在前台,然后你不需要轮询和找到它,然后手动释放它。SetForegroundWindow不保证您的窗口会到前面。有关此问题的详细信息和几种解决方案,请参阅此问题。

相关内容

最新更新