我TMainMenu
在表单上有一个,我想在将一个TMenuItem
添加到TmainMenu
.
TMainMenu.OnChange(Sender: TObject; Source: TMenuItem; Rebuild: Boolean)
似乎不起作用,因为在添加或删除或更新项目时参数值没有区别。我只需要对新项目做出反应。
有任何想法吗?
查看代码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
在运行时从表单的 中分配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;