0

TMainMenu在表单上有一个,我想在将一个TMenuItem添加到TmainMenu.

TMainMenu.OnChange(Sender: TObject; Source: TMenuItem; Rebuild: Boolean)似乎不起作用,因为在添加或删除或更新项目时参数值没有区别。我只需要对新项目做出反应。

有任何想法吗?

4

1 回答 1

4

问题

查看代码TMenuItem.Add()很明显,唯一触发的事件是OnChange. 因此,没有简单而干净的解决方案。

干净的解决方案——重构你的代码

我的第一个想法:您肯定知道何时将菜单项添加到菜单中,是您的代码添加了它。最好的选择是简单地重构代码,这样它就不会直接添加菜单项,而是调用您选择的方法。例如,如果您使用这样的代码:

someMenu.Add(M); // where someMenu is an existing menu item and "M" is the new item

你可以把它重构成这样:

// procedure definition in private section of main form, or somewhere else relevant:
procedure AddSubMenu(const Where, What: TMenuItem);

// Refactor your code to do this:
AddSubMenu(someMenu, M);

// Then in the "AddSubMenu" you can do whatever you want to do for new items:
procedure TFormName.AddSubmenu(const Where, What: TMenuItem);
begin
  // Do your thing.
  // Then do the actual adding of the menu item
  Where.Add(What);
end;

替代解决方案 - 跟踪现有菜单项

使用OnChange你知道被调用的项目,递归地遍历现有列表并对TMenuItems它们做一些事情,这样你就知道你以前见过它们。例如将 设置Tag为 1 - 您会知道带有的项目Tag = 0是新的。或者将所有项目添加到字典中,以便您可以轻松测试哪些项目是新的,哪些项目是预先存在的。

这是一个使用属性来跟踪的示例OnChange处理程序Tag,而不是菜单项是新的还是旧的。确保正确处理菜单的初始创建;例如,在从 DFM 初始化 Menu 之后,并将所有设计时菜单项的 设置为之后,我将OnChange在运行时从表单的 中分配OnCreateTag1

procedure TForm1.MainMenu1Change(Sender: TObject; Source: TMenuItem; Rebuild: Boolean);
var i: Integer;

  procedure VisitMenuItem(const M: TMenuItem);
  begin
    if M.Tag = 0 then
    begin
      // First time I see this TMenuItem!

      // DO my thing
      ShowMessage(M.Caption);

      // Mark the item so I don't "Do my thing" again
      M.Tag := 1;
    end;
  end;

  procedure RecursivelyVisitAllMenuItems(const Root: TMenuItem);
  var i:Integer;
  begin
    VisitMenuItem(Root);
    for i:=0 to Root.Count-1 do
      RecursivelyVisitAllMenuItems(Root.Items[i]);
  end;

begin
  for i:=0 to MainMenu1.Items.Count-1 do
    RecursivelyVisitAllMenuItems(MainMenu1.Items[i]);
end;
于 2013-02-14T09:46:51.323 回答