我的应用程序是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
不保证您的窗口会到前面。有关此问题的详细信息和几种解决方案,请参阅此问题。