【问题标题】:Dynamically create submenu动态创建子菜单
【发布时间】:2017-10-05 03:22:29
【问题描述】:

我有一个带有名为 mnuWindows 的菜单项的 TMainMenu。我希望动态创建子菜单项。我认为这段代码可能会这样做,但它不起作用:

var
  mnuitm: TMenuItem;

mnuitm:=TMenuItem.Create(nil);
mnuitm.Text:='some text';
mnuWindows.AddObject(mnuitm);

当我单击 mnuWINdows 时,什么也没有发生。我哪里错了?

编辑:

点击时子菜单没有显示,因为每次我这样做时,程序都是重新启动的,我没有意识到在这种情况下,两次点击是必要的。第一次单击没有明显地做任何事情,第二次单击下拉子菜单。所以,我承认上面的代码 sn-p 有效。

但我还是有困难。我需要创建几个子菜单项,所以我在 mnuWindows OnClick 事件处理程序中尝试了以下循环:

for I := 0 to TabSet1.Tabs.Count - 1 do
begin
  mnuitm := TMenuItem.Create(mnuWindows);
  mnuitm.Text := TabSet1.Tabs[I].Text;
  mnuitm.OnClick:=MenuItemClick;
  if not mnuWindows.ContainsObject(mnuitm) then
    mnuWindows.AddObject(mnuitm);
end;

上述代码的意图是单击 mnuWindows 项显示选项卡集中的选项卡列表。这段代码在一定程度上起作用。第一次单击时,它会正确列出当前选项卡。但是当我添加一个选项卡并再次单击 mnuWindows 时,新选项卡不会显示在列表中。该列表与以前完全相同。我想知道菜单是否需要以某种方式更新或刷新。我遇到了以下方法

IFMXMenuService.UpdateMenuItem(IItemsContainer, TMenuItemChanges)

但它的文档记录很差,我不确定如何使用它,甚至不确定它是否相关。

EDIT2: 我认为我的帖子上的两次反对票很苛刻。我在网上广泛搜索了如何在 Firemonkey 中动态创建子菜单的示例,但很少。我确实找到了a solution from 2012,但此后的语法变化意味着它在东京 10.2 中不起作用。

【问题讨论】:

  • 您所显示的正是TMenuItem documentation 所说的:“您可以使用 TMenuItem 的 AddObject 过程将子菜单项添加到当前 TMenuItem。”如果它不起作用,file a bug report.
  • 我在我的应用程序中使用完全相同的代码,它适用于我。唯一的区别是我将我的 TMainMenu 作为所有者传递给 TMenuItem.Create()。
  • 您希望 mnuitm 做什么?您没有为其分配 OnClick 处理程序。
  • 你没有给它一个 OnClick 的事件处理程序。您是否希望它通过读心术点击它时神奇地理解您的期望? Delphi很好,但是还没有进步到读懂你的想法的程度;你仍然需要编写代码来让它做事。
  • @Duns 是的,它适用于 10.2 Tokyo。我确实分配了 OnClick 事件,所以这是另一个区别。

标签: delphi firemonkey delphi-10.2-tokyo


【解决方案1】:

试试这样的。正如其他人在上面评论的那样,您需要提供单击菜单项时将发生的事件。另请注意,我在这里的方法需要一堆参数。如果我创建了一个类并以这种方式传递细节会更清晰,但我很久以前写过这个,现在我的代码中有很多地方以这种形式使用它。另外,如果我现在写这个,我会使用一个函数来返回创建的菜单项,以防在特定情况下需要与它进行交互(例如,检查它、分配热键等)

procedure PopMenuAddItem(menu: TPopupMenu; sText: string; iID: integer;
  clickEvent: TNotifyEvent; bEnabled: boolean = true);
var
  NewMenuItem: TmenuItem;
begin
  NewMenuItem := TmenuItem.create(menu);
  with NewMenuItem do
  begin
    Caption := sText;
    tag := iID;
    Enabled := bEnabled;
    OnClick := clickEvent;
 end;
 menu.Items.Add(NewMenuItem);
end;

procedure PopMenuAddSubItem(menuItem: TmenuItem; sText: string; iID: integer;
  clickEvent: TNotifyEvent; bEnabled: boolean = true);
var
  NewMenuItem: TmenuItem;
begin
  NewMenuItem := TmenuItem.create(menuItem);
  with NewMenuItem do begin
    Caption := sText;
    tag := iID;
    Enabled := bEnabled;
    OnClick := clickEvent;
  end;
  menuItem.Add(NewMenuItem);
end;

【讨论】:

  • 谢谢,但那是 VCL 代码而不是 FMX。例如,没有 Add 方法,现在是 AddObject。
【解决方案2】:

我已经回答了我自己的问题。

提醒一下,我想做的是在我的顶级菜单项“Windows”(组件名称“mnuWindows”)下动态创建一个子菜单。在子菜单中,我希望列出选项卡集中的选项卡名称。

尝试在 mnuWindows.OnClick 事件中动态创建子菜单失败。

我的最终解决方案是使用以下方法重建子菜单,并在创建新选项卡、删除选项卡或重命名选项卡后立即调用此方法:

procedure Form1.ReBuildWindowsMenu;
var
  mnuitm: TMenuItem;
  I: Integer;
begin
  mnuWindows.Clear; // removes submenu items
  for I := 0 to TabSet1.Tabs.Count - 1 do
  begin
    mnuitm := TMenuItem.Create(MainMenu1);
    mnuitm.Caption:= TabSet1.Tabs[I].Text; // submenu item displays same text as associated tab
    mnuitm.OnClick := MenuItemClick; // makes the associated tab active
    mnuWindows.AddObject(mnuitm);
  end;
end;

OnClick 处理程序包含单个语句

TabSet1.ActiveTabIndex:=(Sender as TMenuItem).Index;

这个简单的解决方案使我的 Windows 列表与选项卡集中的选项卡完美同步。我打算使用类似的方法将最近使用的 (MRU) 文件列表放入我的文件菜单中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-15
    • 2015-04-08
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    • 1970-01-01
    • 2021-08-02
    • 2014-12-08
    相关资源
    最近更新 更多