2

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?

  • `m.Free;` works for me, as well as `m.Release;` – Tom Brunberg Feb 07 '17 at 08:30
  • @TomBrunberg: Works for me too, at least with Win32 as target. – MartynA Feb 07 '17 at 08:44
  • Which platform are you trying this on? – DNR Feb 07 '17 at 09:19
  • @MartynA Ahh yes, maybe he is on a mobile target. I guess nilling would do in that case, but I can't check. – Tom Brunberg Feb 07 '17 at 09:37
  • If your target is a mobile, then your question is a duplicate of this: http://stackoverflow.com/questions/27818697/how-to-free-a-component-in-android-ios/27819789#27819789 – Tom Brunberg Feb 07 '17 at 09:52
  • My target platforms are Windows and MacOS, no mobile. Free removes for me only the main menu item (the one visible in the mainmenu toolbar). If I try to release a submenu, its still there and visible. –  Feb 08 '17 at 09:18
  • I create a new multidevice project, add a TMainMenu, add to this a Menu (Menuitem1), and to that menu a submenu (MenuSubItem1). Then I call MenuSubItem1.Free, and its still there, then I tried MenuSubItem1.Parent:=nil; and its still there, and MenuItem1.RemoveObject(MenuSubItem1); and its still there... then I did MenuItem1.visible:=false; and Menuitem1.visible=true; and then it vanish! And thats the only issue I have, no other control cause any problem... –  Feb 08 '17 at 09:36

2 Answers2

0

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;
Peter-John Jansen
  • 603
  • 1
  • 7
  • 26
  • Doesn't work for me, the submenu item is still there and visible. –  Feb 08 '17 at 09:20
  • Now that I know that you are not targeting mobile, you must use `disposeOf` which will free the object seeing as Windows does not make use of ARC, and memory management is done manually. DisposeOf will still work on Mobile, but it is the less preferred method, see David's answer here : http://stackoverflow.com/questions/27818697/how-to-free-a-component-in-android-ios/27819789#27819789 – Peter-John Jansen Feb 08 '17 at 12:38
  • None of the methods I tried remove the submenu item, also not disposeOf. After disposeOf, I click on the menu and its submenu is still there. It only is removed when I set the submenu items visible property to false and back to true. There is no issue with th TMenuBar, items added to that will be removed without any issue, just the TMainMenu cause the issue for me. –  Feb 08 '17 at 14:42
  • After more than 2 weeks trial and error, I still couldn't find a working solution. Isn't there anybody facing the dame problem and might already found a working solution? –  Mar 02 '17 at 01:50
0

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.