Reputation: 1122
I have a TMainMenu
on a form and I want to add an event when an TMenuItem
is added to the TmainMenu
.
TMainMenu.OnChange(Sender: TObject; Source: TMenuItem; Rebuild: Boolean)
doesn't seem to work because there is no difference in params values when adding or removing or updateing items. And I need to react only to new items.
Any ideas?
Upvotes: 0
Views: 360
Reputation: 25678
Looking at the code for TMenuItem.Add()
it's clearly obvious that the only event that's triggered is the OnChange
. Because of that there's no easy and clean solution.
My first thought: surely you know when a menu item is added to the menu, it's your code that's adding it. The best option would be to simply re-factor the code so it doesn't directly add the menu item but calls a method of your choice. For example, if you're using code like this:
someMenu.Add(M); // where someMenu is an existing menu item and "M" is the new item
you could refactor it to something like this:
// 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;
Use the OnChange
item that you know gets called, recursively walk the list of existing TMenuItems
and do something with them so you know you've seen them before. For example set the Tag
to 1 - you'll know items with Tag = 0
are new. Or add all items into a Dictionary so you can easily test what items are new and what items are pre-existing.
Here's an example OnChange
handler using the Tag
property to track rather a menu item is New or Old. Make sure you handle the initial creating of the Menu properly; For example, I'd assign the OnChange
at runtime, from the form's OnCreate
, after the Menu has been initialized from the DFM and after setting the Tag
for all the design-time menu items to 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;
Upvotes: 4