我在表单上有一个TMainMenu
,我想在TMenuItem
添加TmainMenu
时添加一个事件。
TMainMenu.OnChange(Sender: TObject; Source: TMenuItem; Rebuild: Boolean)
似乎不起作用,因为在添加或删除或更新项目时,params值没有区别。我只需要对新项目做出反应。
有什么想法吗?
答案 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;