I’m using Python 3.7 with wxPython 4.0.4. Having a problem with menuBar when I only want a single clickable item. It’s a menu bar with a menu object appended but no menu items are in the menu object. There is no drop-down and no id to bind with. The menuBar object eats the onClick event. I just want to detect when the “Run” item is clicked. Is there any way of catching this event?
1 Answer
Whilst the real answer should be, add a menu item called Run to your Run menu, because that enables the user to choose to run the function, rather than accidently running it by clicking on the menubar, the answer is yes you can.
Bind to the event wx.EVT_MENU_OPEN
import wx
import wx.stc
class MyApp(wx.App):
def OnInit(self):
self.frame = MenuFrame(None, title="Menus and MenuBars")
self.SetTopWindow(self.frame)
self.frame.Show()
return True
ID_READ_ONLY = wx.NewId()
class MenuFrame(wx.Frame):
def __init__(self, *args, **kwargs):
super(MenuFrame, self).__init__(*args, **kwargs)
# Attributes
self.panel = wx.Panel(self)
self.txtctrl = wx.stc.StyledTextCtrl(self.panel,
style=wx.TE_MULTILINE)
# Layout
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(self.txtctrl, 1, wx.EXPAND)
self.panel.SetSizer(sizer)
self.CreateStatusBar() # For output display
# Setup the Menu
menub = wx.MenuBar()
# File Menu
filem = wx.Menu()
filem.Append(wx.ID_NEW, "New")
filem.Append(wx.ID_OPEN, "Open")
filem.Append(wx.ID_SAVE, "Save")
filem.Append(wx.ID_SAVEAS, "Save_As")
menub.Append(filem, "&File")
# Edit Menu
editm = wx.Menu()
editm.Append(wx.ID_UNDO, "Undo")
editm.Append(wx.ID_REDO, "Redo")
editm.Append(wx.ID_COPY, "Copy")
editm.Append(wx.ID_CUT, "Cut")
editm.Append(wx.ID_PASTE, "Paste")
editm.Append(wx.ID_SELECTALL, "SelectAll")
editm.AppendSeparator()
editm.Append(ID_READ_ONLY, "Read Only",
kind=wx.ITEM_CHECK)
menub.Append(editm, "Edit")
# History Menu
historym = wx.Menu()
historym.Append(wx.ID_PREVIEW, "Recent")
menub.Append(historym, "&History")
# Help Menu
helpm = wx.Menu()
helpm.Append(wx.ID_HELP_INDEX, "Hint")
helpm.Append(wx.ID_ABOUT, "About")
menub.Append(helpm, "&Help")
# Run Menu
runm = wx.Menu()
menub.Append(runm,"&Run")
self.SetMenuBar(menub)
# Event Handlers
self.Bind(wx.EVT_MENU, self.OnMenu)
self.Bind(wx.EVT_MENU_OPEN, self.OnMenu)
def OnMenu(self, event):
"""Handle menu clicks"""
evt_id = event.GetId()
if evt_id == 0:
obj = event.GetMenu()
if obj.GetTitle() == "&Run":
self.txtctrl.AddText('Running program\n')
else:
self.txtctrl.AddText("Menu item "+str(evt_id)+" selected\n")
if __name__ == "__main__":
app = MyApp()
app.MainLoop()
You have a choice of:
- EVT_MENU_OPEN: A menu is about to be opened. On Windows, this is only sent once for each navigation of the menubar (up until all menus have closed).
- EVT_MENU_CLOSE: A menu has been just closed. Notice that this event is currently being sent before the menu selection ( wxEVT_MENU ) event, if any.
- EVT_MENU_HIGHLIGHT: The menu item with the specified id has been highlighted: used to show help prompts in the status bar by wx.Frame
- EVT_MENU_HIGHLIGHT_ALL: A menu item has been highlighted, i.e. the currently selected menu item has changed.
That said, I still think that you should add a Run menu item to the Run menu

2 Comments
dw1
This works but I haven't found a way to prevent the empty submenu from opening or close it when clicked, and an attempted hack to remove or replace the menu in the event crashes the program.
Rolf of Saxony
@dw1 The issue is really that you want a Cat to bark or a
menu to act, just for a single entry, as a toolbar. Perhaps adding a title to the menu will make it look a little better, rather than having it blank. i.e. runm = wx.Menu("Run Instantly")