However, the Remove() method doesn’t take a wxMenuItem, so the submenu can’t be removed.
What’s wrong here? This line fails: self.file_menu.Remove(self.sub_menu)
import wx
class MyFrame(wx.Frame):
def __init__(self, *args, **kw):
super(MyFrame, self).__init__(*args, **kw)
# Create a menu bar
self.menu_bar = wx.MenuBar()
# Create a main menu
self.file_menu = wx.Menu()
# Create a submenu
self.sub_menu = wx.Menu()
self.add_sub_menu_items()
# Add the submenu to the main menu
self.file_menu.AppendSubMenu(self.sub_menu, "Submenu")
# Add the main menu to the menu bar
self.menu_bar.Append(self.file_menu, "&File")
# Set the menu bar for the frame
self.SetMenuBar(self.menu_bar)
# Create a button to destroy and recreate the submenu
self.panel = wx.Panel(self)
self.button = wx.Button(self.panel, label="Recreate Submenu")
self.button.Bind(wx.EVT_BUTTON, self.on_button_click)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.button, 0, wx.ALL | wx.CENTER, 5)
self.panel.SetSizer(sizer)
def add_sub_menu_items(self):
self.sub_menu.Append(wx.ID_ANY, "Item 1")
self.sub_menu.Append(wx.ID_ANY, "Item 2")
self.sub_menu.Append(wx.ID_ANY, "Item 3")
def on_button_click(self, event):
# Remove the existing submenu
self.file_menu.Remove(self.sub_menu)
# Create a new submenu
self.sub_menu = wx.Menu()
self.add_sub_menu_items()
# Add the new submenu to the main menu
self.file_menu.AppendSubMenu(self.sub_menu, "Submenu")
# Refresh the menu bar to apply changes
self.menu_bar.Refresh()
if __name__ == "__main__":
app = wx.App(False)
frame = MyFrame(None, title="Recreate Submenu Example")
frame.Show(True)
app.MainLoop()
This appears to work using wxPython 4.2.2 gtk3 (phoenix) wxWidgets 3.2.6 + Python 3.12.3 + Linux Mint 22.1
def on_button_click(self, event):
# Remove the existing submenu
id = self.file_menu.FindItem("Submenu")
self.file_menu.Remove(id)
# Create a new submenu
self.sub_menu = wx.Menu()
self.add_sub_menu_items()
# Add the new submenu to the main menu
self.file_menu.AppendSubMenu(self.sub_menu, "New Submenu")
# Refresh the menu bar to apply changes
self.menu_bar.Refresh()
However, the docs say that Remove() doesn’t delete the associated C++ object, so I’m not sure if it will cause a memory leak.
Below is an alternative example that keeps a reference to the Menu Item associated with the Sub Menu. I added a numeric suffix just to demonstrate that it is actually creating a new Sub Menu each time you click the button.
import wx
class MyFrame(wx.Frame):
def __init__(self, *args, **kw):
super(MyFrame, self).__init__(*args, **kw)
# Create a menu bar
self.menu_bar = wx.MenuBar()
# Create a main menu
self.file_menu = wx.Menu()
# Create a submenu
self.sub_menu = wx.Menu()
self.add_sub_menu_items()
self.count = 1
# Add the submenu to the main menu
self.sub_menu_item = self.file_menu.AppendSubMenu(self.sub_menu, f"Submenu {self.count}")
# Add the main menu to the menu bar
self.menu_bar.Append(self.file_menu, "&File")
# Set the menu bar for the frame
self.SetMenuBar(self.menu_bar)
# Create a button to destroy and recreate the submenu
self.panel = wx.Panel(self)
self.button = wx.Button(self.panel, label="Recreate Submenu")
self.button.Bind(wx.EVT_BUTTON, self.on_button_click)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.button, 0, wx.ALL | wx.CENTER, 5)
self.panel.SetSizer(sizer)
def add_sub_menu_items(self):
self.sub_menu.Append(wx.ID_ANY, "Item 1")
self.sub_menu.Append(wx.ID_ANY, "Item 2")
self.sub_menu.Append(wx.ID_ANY, "Item 3")
def on_button_click(self, event):
# Remove the existing submenu
item = self.file_menu.Remove(self.sub_menu_item)
# Create a new submenu
self.sub_menu = wx.Menu()
self.add_sub_menu_items()
# Add the new submenu to the main menu
self.count += 1
self.sub_menu_item = self.file_menu.AppendSubMenu(self.sub_menu, f"Submenu {self.count}")
# Refresh the menu bar to apply changes
self.menu_bar.Refresh()
if __name__ == "__main__":
app = wx.App(False)
frame = MyFrame(None, title="Recreate Submenu Example")
frame.Show(True)
app.MainLoop()