默认情况下,当您从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.