Delphi firemonkey how to remove a menuitem programmatically?

809 Views Asked by At

How can I remove a menuitem I dynamically added to a menu?

I add dynamically menu items with for example:

m:=TMenuItem.Create(nil);
m.Text:='bla bla bla';
mnuMain.AddObject(m);

I could not find ANY function to remove the entry again. I tried delete, free, removeobject etc. and the item is still nor removed and still visible. What is the trick?

2

There are 2 best solutions below

1
On

I faced the same issue: TMenuItem.RemoveObject is not working and the private member FContent of TMenuView is not accessable without tricks over RTTI. That is why I build my own workaround by using a stringlist that stores the remaining menu child items before I call TMenuItem.Clear:

function RemoveFromMenu(mnuMain: TMenuItem; const MenuText: string);
var
  list: TStringList;
  c: integer;
  Menu: TMenuItem;
begin
  list := TStringList.Create;
  try
    for c := 0 to mnuMain.ItemsCount - 1 do
    if mnuMain.Items[c].Text <> MenuText then
      list.Add(mnuMain.Items[c].Text);
    mnuMain.Clear;
    for c := 0 to list.Count - 1 do
    begin
      Menu := TMenuItem.Create(self);
      Menu.Text := list[c];
      Menu.OnClick := mnuMainSubMenuClick; // The menu event handler
      mnuMain.InsertObject(0, Menu);
    end;
  finally
    list.Free;
  end;
end;

In case your sub menu have for each menu item an own menu handler than you have also store this event handler. In such situations a generic list of TMenuItem (TList< TMenuItem >) would be a better approach than using the string list.

4
On

If you are adding a item like so :

var
    M : TMenuItem;
begin
    M := TMenuItem.Create(nil);
    M.Text := 'Bla Bla Bla';
    MenuBar1.AddObject(M);

Then you are just giving it a parent, just set the parent of the menu items to nil ARC will then swoop in and do the rest seeing as there are no more references to the object

Just write a loop to go through and set all the parents to nil/ Or if you are targeting Windows as well (Or only Windows) in your code, make use of DisposeOf, or make use of compiler directives

var
  I: Integer;
begin
    for I :=  MenuBar1.ItemsCount-1 downto 0 do
    begin
       {$IFNDEF AUTOREFCOUNT}
         MenuBar1.Items[I].disposeOf;
       {$ELSE}
         MenuBar1.Items[I].parent := nil;
       {$ENDIF}
    end;
end;