在运行时创建弹出式菜单

4
我想简单地创建一个弹出菜单(或上下文菜单),向其中添加一些项目,并在鼠标位置显示它。我找到的所有示例都是使用设计器实现的。但我是从一个DLL插件中进行操作,因此没有表单/设计器可用。用户将从主应用程序中点击一个按钮,该按钮将调用下面的execute过程。我只想让类似于右键菜单的东西出现。
我的代码显然不起作用,但我希望有一个在运行时创建弹出菜单的示例,而不是在设计时创建。
procedure TPlugIn.Execute(AParameters : WideString);
var
  pnt: TPoint;
  PopupMenu1: TPopupMenu;
  PopupMenuItem : TMenuItem;
begin
  GetCursorPos(pnt);
  PopupMenuItem.Caption := 'MenuItem1';
  PopupMenu1.Items.Add(PopupMenuItem);
  PopupMenuItem.Caption := 'MenuItem2';
  PopupMenu1.Items.Add(PopupMenuItem);
  PopupMenu1.Popup(pnt.X, pnt.Y);

end;

1
@Warren,有一些静态类型语言,声明变量就足以初始化它。C++是一个明显的例子。 - David Heffernan
1
@ike预计插件DLL中的GUI代码会出现问题。 - David Heffernan
-1. "My code obviously doesn't work". 始终用复制粘贴方式提供完整的错误消息描述。 - David Heffernan
1
我的代码显然不起作用。为什么,为什么?看起来你知道答案!那还问什么? - NGLN
@DavidHeffernan - 你能发布一个解释“插件DLL中GUI代码可能会出现问题”的资源链接吗?谢谢 - Gabriel
1
@Rigel 这就是为什么存在包的原因。使用 DLL 而不是包来制作插件意味着 DLL 与主机可执行文件有一个单独的 VCL 实例。经典症状是类型标识不像预期那样工作。例如,在上面的代码中,TPopupMenu 在 DLL 中与主机中完全相同命名的类型不同,因为存在不同的 VCL 实例。但问题还有很多。如果包不是可行的选项,那么您需要做更多的工作来启用插件。 - David Heffernan
1个回答

12

在Delphi中,您必须先创建一个类的实例才能使用它们。下面的代码创建了一个弹出菜单,并向其中添加了一些项目(包括一个点击事件处理程序),然后将其分配给表单。请注意,您必须像我所做的那样声明(并编写)HandlePopupItemClick事件。

在接口部分(将Menus添加到uses子句中):

type
  TForm1 = class(TForm)
    // Double-click the OnCreate in the Object Inspector Events tab. 
    // It will add this item.
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    // Add the next two lines yourself, then use Ctrl+C to
    // generate the empty HandlePopupItem handler
    FPopup: TPopupMenu;      
    procedure HandlePopupItem(Sender: TObject);
  public
    { Public declarations }
  end;

implementation

// The Object Inspector will generate the basic code for this; add the
// parts it doesn't add for you.
procedure TForm1.FormCreate(Sender: TObject);
var
  Item: TMenuItem;
  i: Integer;
begin
  FPopup := TPopupMenu.Create(Self);
  FPopup.AutoHotkeys := maManual;
  for i := 0 to 5 do
  begin
    Item := TMenuItem.Create(FPopup);
    Item.Caption := 'Item ' + IntToStr(i);
    Item.OnClick := HandlePopupItem;
    FPopup.Items.Add(Item);
  end;
  Self.PopupMenu := FPopup;
end;

// The Ctrl+C I described will generate the basic code for this;
// add the line between begin and end that it doesn't.
procedure TForm1.HandlePopupItem(Sender: TObject);
begin
  ShowMessage(TMenuItem(Sender).Caption);
end;

现在我将留给你去想出如何完成剩下的部分(创建并在特定位置显示它)。

我在同一个过程中创建并显示了上下文菜单。我不需要释放任何东西,对吗? - ikathegreat
我无法回答这个问题,因为我不知道你具体做了什么。在我发布的代码中,菜单属于表单(TPopupMenu.Create(Self) 在表单方法中表示表单是所有者,并负责释放它),而各个项目属于菜单(TMenuItem.Create(FPopup))。当项目被点击时,您的菜单必须存在足够长的时间,以使事件处理程序仍然有效。 - Ken White
1
我会在插件的构造函数中创建弹出菜单。Execute函数将只获取光标位置并在此位置显示菜单,插件的析构函数可以释放弹出菜单。我不知道这是否适用于您,因为除了您在问题中发布的信息外,我没有其他信息。 - Ken White
是的,抱歉缺乏细节,部分原因是试图弄清楚如何描述。但添加destructor并添加FPopup.Free;就解决了问题。在那之前,我的应用程序一直崩溃。谢谢。 - ikathegreat
3
我无法理解像“Warren P”那样发表评论时人们为什么会如此攻击性。这种傲慢是从哪里来的?他们忘记了自己曾经是新手,也犯过同样的基本错误。如果你没有必要的耐心来处理这些基本问题,我认为最好不要发表评论。从“Ken White”的回答中学习,他的回答直接、简单、客观,并且实际上帮助了用户解决了问题。 - user2383818
FPopUp.CreateMenuItem 也应该可以工作。 - Gabriel

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