Dynamically create submenu

时间:2017-10-05 03:22:29

标签: delphi firemonkey delphi-10.2-tokyo

I have a TMainMenu with a menu item called mnuWindows. I wish to create submenu items dynamically. I thought this code might do it but it doesn't work:

var
  mnuitm: TMenuItem;

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

When I click on mnuWIndows, nothing happens. Where am i going wrong?

EDIT:

The submenu was not displaying on clicking because each time I did so, the program had been freshly started and I didn't realize that under these circumstances, two clicks are necessary. The first click doesn't visibly do anything and the second click drops down the submenu. So, I concede the code snippet above works.

But I still have a difficulty. I need to create several submenu items so I tried the following loop inside the mnuWindows OnClick event handler:

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;

The intent of the above code is that clicking the mnuWindows item displays a list of the tabs in a tabset. This code works up to a point. On first being clicked, it correctly lists the current tabs. But when I add a tab and click on mnuWindows again, the new tab is not shown in the list. The list is exactly as before. I wondered if the menu needed updating or refreshing somehow. I came across the following method

IFMXMenuService.UpdateMenuItem(IItemsContainer, TMenuItemChanges)

but it is poorly documented and I'm not sure how to use it or even whether it is relevant.

EDIT2: I thought the two down votes on my post were harsh. I have searched the web extensively for an example of how to dynamically create submenus in Firemonkey and there is very little. I did find a solution from 2012的文字,但从那时起语法更改意味着它在东京10.2中不起作用。

2 个答案:

答案 0 :(得分:0)

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

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;

答案 1 :(得分:0)

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

提醒一下,我想要做的是在我的顶级菜单项下动态创建一个子菜单" 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.Text := 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列表与tabset中的选项卡完美同步。我计划使用类似的方法将最近使用的(MRU)文件列表放入我的文件菜单。