delphi – 如何在不关闭菜单的情况下选择菜单项?

前端之家收集整理的这篇文章主要介绍了delphi – 如何在不关闭菜单的情况下选择菜单项?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
默认情况下,当您从TMainMenu或TPopupMenu等选择一个项目时,该菜单在单击后关闭。我想改变这个行为,所以当我在菜单项上选择时,菜单不会关闭,但是在最后一次点击时保持可见和打开状态,如果需要,更容易选择另一个菜单项。当然,将焦点切换到另一个控件应该像常规一样隐藏菜单,但是如果焦点仍然在菜单上保持可见。

如果可能,我希望这个行为只能在指定的菜单项上工作。换句话说,如果我可以使所有的菜单项正常工作,但如果我指定一个或两个菜单项,这些将不会在选择时关闭菜单

我想这样做的原因就是这样,我的应用程序中有一个Preferences表单,可以配置很多选项,通常的东西等等,而且在主窗体中我有一些常用的更常用的选项设置在TMainMenu。我的菜单中的这些常见选项,我希望能够选择而不关闭菜单,以便可以选择其他选项,而无需浏览菜单项。

有没有一个标准化的方法实现这一点?

谢谢

克雷格。

解决方法

在下面的代码中,当右键单击表单上的面板时,会弹出一个包含三个项目的弹出菜单。第一个项目正常运行,其他两个项目也会触发他们的点击事件,但是弹出菜单没有关闭

弹出窗口是以“TrackPopupMenu”启动的,如果您想使用“OnPopup”事件,或需要使用具有非关闭项目的子菜单,请参阅我发布到您的问题的评论中的链接。适应主菜单代码也不难。

我没有评论代码不推广使用方法,因为它使用了一个未记录的消息,我也觉得这有点复杂..

unit Unit1;

interface

uses
  Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,Dialogs,Menus,ExtCtrls;

type
  TForm1 = class(TForm)
    PopupMenu1: TPopupMenu;
    Item1Normal1: TMenuItem;
    Item2NoClose1: TMenuItem;
    Item3NoClose1: TMenuItem;
    Panel1: TPanel;
    procedure Panel1ContextPopup(Sender: TObject; MousePos: TPoint;
      var Handled: Boolean);
  private
    FGetPopupWindowHandle: Boolean;
    FPopupWindowHandle: HWND;
    OrgPopupWindowProc,HookedPopupWindowProc: Pointer;
    FSelectedItemID: UINT;
    procedure WmInitMenuPopup(var Msg: TWMInitMenuPopup); message WM_INITMENUPOPUP;
    procedure WmEnterIdle(var Msg: TWMEnterIdle); message WM_ENTERIDLE;
    procedure WmMenuSelect(var Msg: TWMMenuSelect); message WM_MENUSELECT;
    procedure PopupWindowProc(var Msg: TMessage);
    procedure MenuSelectPos(Menu: TMenu; ItemPos: UINT; out CanClose: Boolean);
    procedure MenuSelectID(Menu: TMenu; ItemID: UINT; out CanClose: Boolean);
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Panel1ContextPopup(Sender: TObject; MousePos: TPoint;
  var Handled: Boolean);
var
  Pt: TPoint;
begin
  Pt := (Sender as TPanel).ClientToScreen(MousePos);
  TrackPopupMenu(PopupMenu1.Handle,Pt.X,Pt.Y,Handle,nil);
end;

procedure TForm1.WmInitMenuPopup(var Msg: TWMInitMenuPopup);
begin
  inherited;
  if Msg.MenuPopup = PopupMenu1.Handle then
    FGetPopupWindowHandle := True;
end;

procedure TForm1.WmEnterIdle(var Msg: TWMEnterIdle);
begin
  inherited;
  if FGetPopupWindowHandle then begin
    FGetPopupWindowHandle := False;
    FPopupWindowHandle := Msg.IdleWnd;

    HookedPopupWindowProc := classes.MakeObjectInstance(PopupWindowProc);
    OrgPopupWindowProc := Pointer(GetWindowLong(FPopupWindowHandle,GWL_WNDPROC));
    SetWindowLong(FPopupWindowHandle,GWL_WNDPROC,Longint(HookedPopupWindowProc));
  end;
end;

procedure TForm1.WmMenuSelect(var Msg: TWMMenuSelect);
begin
  inherited;
  if Msg.Menu = PopupMenu1.Handle then
    FSelectedItemID := Msg.IDItem;
end;


const
  MN_BUTTONDOWN = $01ED;

procedure TForm1.PopupWindowProc(var Msg: TMessage);
var
  NormalItem: Boolean;
begin
  case Msg.Msg of
    MN_BUTTONDOWN:
      begin
        MenuSelectPos(PopupMenu1,UINT(Msg.WParamLo),NormalItem);
        if not NormalItem then
          Exit;
      end;
    WM_KEYDOWN:
      if Msg.WParam = VK_RETURN then begin
        MenuSelectID(PopupMenu1,FSelectedItemID,NormalItem);
        if not NormalItem then
          Exit;
      end;
    WM_DESTROY:
      begin
        SetWindowLong(FPopupWindowHandle,Longint(OrgPopupWindowProc));
        classes.FreeObjectInstance(HookedPopupWindowProc);
      end;
  end;

  Msg.Result := CallWindowProc(OrgPopupWindowProc,FPopupWindowHandle,Msg.Msg,Msg.WParam,Msg.LParam);

end;


procedure TForm1.MenuSelectID(Menu: TMenu; ItemID: UINT; out CanClose: Boolean);
var
  Item: TMenuItem;
begin
  CanClose := True;
  Item := Menu.FindItem(ItemID,fkCommand);
  if Assigned(Item) then begin
    // Menu Item is clicked
    Item.Click;
//    Panel1.Caption := Item.Name;
    CanClose := Item = Item1Normal1;
  end;
end;

procedure TForm1.MenuSelectPos(Menu: TMenu; ItemPos: UINT; out CanClose: Boolean);
begin
  MenuSelectID(Menu,GetMenuItemID(Menu.Handle,ItemPos),CanClose);
end;

end.

猜你在找的Delphi相关文章