移出它时关闭TPopupMenu - 在(始终在顶部)应用程序外部单击时删除其浮动行为

时间:2016-10-09 13:52:38

标签: delphi delphi-7 delphi-xe5

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

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

试图跟随很多文章,甚至从D7变为XE5都没有成功。检查过这个问题:Automatically Hide or Close PopUp Menu when Mouse Pointer is outside it - Delphi我的延迟定时器或托盘控制并不复杂。

具体来说,借用解决方案,我做到了这一点:

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)轮询光标位置,以检测光标是否移出菜单(mastermenu)。如果它移出,我将发出.closeMenu()

但是,此代码抛出 - 在FindWindow()最后一个参数的D7 / XE5中的字符串,pAnsiChar / pwidestring不匹配。也许我应该使用FindWindowEx? 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.

1 个答案:

答案 0 :(得分:2)

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

resp, err = client.Get("someurl")
var urls []string

if err != nil {
    log.Fatal(err)
}

doc, err := html.Parse(strings.NewReader(resp.Body))
if err != nil {
    log.Fatal(err)
}

var f func(*html.Node)
f = func(n *html.Node) {
    if n.Type == html.ElementNode && n.Data == "a" {
        for _, a := range n.Attr {
            if a.Key == "href" {
                fmt.Println(a.Val)

                if strings.Contains(a.Val, "somestring") {
                    urls = append(urls, a.Val)
                }

                break
            }
        }
    }
    for c := n.FirstChild; c != nil; c = c.NextSibling {
        f(c)
    }
}
f(doc)

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

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

正如你所链接的页面上的几个地方所提到的,为了正常发布弹出窗口,当你弹出菜单时你的窗口必须在前台,然后你不需要轮询并找到它然后手动释放它。 ... 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; 不保证您的窗口会出现在前面。有关此问题和多个解决方案的详细信息,请参阅this question