TMainMenu的OnNewItem事件

时间:2013-02-14 09:24:01

标签: delphi menuitem

我在表单上有一个TMainMenu,我想在TMenuItem添加TmainMenu时添加一个事件。

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

有什么想法吗?

1 个答案:

答案 0 :(得分: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属性来跟踪菜单项是New还是Old。确保正确处理菜单的初始创建;例如,在从DFM初始化菜单后以及为所有设计时菜单设置OnChange之后,我将在运行时从表单的OnCreate分配Tag项目到1

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;