如何检测 TMenuItem 的右键单击?

6

平台:Delphi 2010

  1. 将TMainMenu拖放到Form1上。
  2. 将TPopupMenu拖放到Form1上。
  3. 添加MainMenu1和PopupMenu项。 (MainMenu --> 文件 --> Item1,PopupMenu --> 弹出项1)
  4. Item1.onRightClick显示PopupMenu。
  5. 按F9键。
  6. 在文件-->项目1上右键单击,选择弹出菜单中的项目1,然后进行其他操作。
object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 222
  ClientWidth = 447
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  Menu = MainMenu1
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object MainMenu1: TMainMenu
    Left = 136
    Top = 64
    object file1: TMenuItem
      Caption = 'file'
      object recentfile1: TMenuItem
        Caption = 'item 1'
      end
    end
  end
  object PopupMenu1: TPopupMenu
    Left = 24
    Top = 136
    object popupitem1: TMenuItem
      Caption = 'popup item'
      OnClick = popupitem1Click
    end
  end
end

3
在菜单项上添加右键菜单会与菜单的预期行为极不相符。为什么不将额外的菜单项放在子菜单中呢? - Michael Madsen
1
@Michael:然而,在微软Windows中这种行为十分普遍,如果弹出菜单的项是文件(某种意义上)。在Windows 7中,单击“开始/最近使用的程序”选项。在此,您可以右键单击任何菜单项并获得新的弹出菜单。 - Andreas Rejbrand
2
我说这不是预期的行为,而不是没有听说过。规则总有例外,但这个问题中没有任何迹象表明它应该是其中之一。例如,在 Word 中,您的 MRU 列表上不会有右键选项。(不,我不会计算 2007 年和 2010 年,因为它们不是常规菜单 - 启动菜单也不是。) - Michael Madsen
1
@Andreas:不需要为EE付费:http://en.wikipedia.org/wiki/Experts-Exchange#Viewing_solutions_without_membership - Uli Gerhardt
3
@Michael - 因提到工作示例不是常规菜单而赞扬你的回答。但是,这是一个技术性问题,并不一定需要证明其上下文。换句话说,问题中没有任何内容表明该设计对于 OP 不合理-它只是一个简化的问题陈述。 - Sertac Akyuz
显示剩余6条评论
1个回答

3
以下是下面示例的菜单结构。
File1           Edit1
  FileItem11      EditItem11
  FileItem21      EditItem21

还有两个弹出式菜单项。代码:

type
  TForm1 = class(TForm)
    MainMenu1: TMainMenu;
    File1: TMenuItem;
    FileItem11: TMenuItem;
    FileItem21: TMenuItem;
    Edit1: TMenuItem;
    EditItem11: TMenuItem;
    EditItem21: TMenuItem;
    PopupMenu1: TPopupMenu;
    PopupItem11: TMenuItem;
    PopupItem21: TMenuItem;
    procedure PopupItem11Click(Sender: TObject);
    procedure PopupItem21Click(Sender: TObject);
  private
    FSelectedItem: TMenuItem;
    FTracking: Boolean;
    procedure MenuRButtonUp(var Msg: TMessage); message WM_MENURBUTTONUP;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TForm1 }

procedure TForm1.MenuRButtonUp(var Msg: TMessage);
var
  Cmd: UINT;
begin
  if not FTracking then
    FSelectedItem :=
        MainMenu1.FindItem(GetMenuItemID(Msg.LParam, Msg.WParam), fkCommand);

  if (not FTracking) and (FSelectedItem <> nil) then begin
    FTracking := True;
    LongBool(Cmd) := TrackPopupMenuEx(PopupMenu1.Handle,
                            TPM_RECURSE or TPM_BOTTOMALIGN or TPM_RETURNCMD,
                            Mouse.CursorPos.X, Mouse.CursorPos.Y, Handle, nil);
    FTracking := False;
    if Cmd <> 0 then
      PopupMenu1.DispatchCommand(Cmd);
  end;
  inherited;
end;

procedure TForm1.PopupItem11Click(Sender: TObject);
begin
  Caption := 'Popup Item 1 clicked on ' + FSelectedItem.Caption;
end;

procedure TForm1.PopupItem21Click(Sender: TObject);
begin
  // whatever..
  Caption := 'Popup Item 2 clicked on ' + FSelectedItem.Caption;
end;

2
“-1”表示标准菜单不支持右键单击,但实际上是支持的。可以通过“WM_MENURBUTTONUP”消息来实现这一点,该消息专门为此目的而引入:http://msdn.microsoft.com/en-us/library/ms647610.aspx。在http://www.deja.com的档案中搜索,有很多使用Delphi中的“WM_MENURBUTTONUP”的示例。 - Remy Lebeau
1
做得好,代码很棒。非常感谢大家。附言:@sertac bey,感谢您的关注和关心 :) - delphi2010
@Remy - 好的,我删掉了我说的话。 - Sertac Akyuz
有没有办法扩展这个功能,使其也能处理顶部菜单项(File1和Edit1)的右键单击? - Aladdin
@Aladdin - 看起来不是这样。可能需要干预WM_NCRBUTTONUP,检查HTMENU的命中测试,然后为每个项目调用GetMenuBarInfo以找到释放右键的项目。 - Sertac Akyuz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接