Search code examples
linuxwindowspython-3.xwxpythonwxwidgets

MenuItem bitmaps raises an assert failure …


I am trying to have a nice bitmap of a gear in front of the Preferences menu item. This is how I think it should be coded:

    menubar = wx.MenuBar()
    fileMenu = wx.Menu()
    preferences = wx.MenuItem(text="Preferences",
                              helpString="Opens preferences dialog.",
                              kind=wx.ITEM_NORMAL)
    gear = wx.Bitmap(os.path.join(os.path.dirname(__file__), 'gear.png'))
    preferences.SetBitmap(gear)
    self.shcfg = fileMenu.Append(preferences)

However, this is wrong as I get a

Traceback (most recent call last):                                              
  File "gui.py", line 193, in <module>                                          
    GUI(None)                                                                   
  File "gui.py", line 117, in __init__                                          
    self.InitUI()                                                               
  File "gui.py", line 129, in InitUI                                            
    preferences.SetBitmap(gear)                                                 
wx._core.wxAssertionError: C++ assertion "Assert failure" failed at /tmp/pip-build-sc_vd1aj/wxPython/ext/wxWidgets/src/gtk/menu.cpp(729) in SetBitmap(): only normal menu items can have bitmaps 

What am I doing wrong?


Solution

  • You are using Append rather than AppendItem

    I suppose that there any number of ways to put a menu together but I have found that, all menu items require an Id.
    For predefined wx id's it is straight forward as you can simply append them as they come not only with an in-built Id but also an image.
    For custom images I use the method below, which has consistently worked for me.
    Note that I have used both predefined Id's and custom Id's in this sample code.
    I have included a variant of your code below

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    import wx
    import os
    class MainWindow(wx.Frame):
        def __init__(self, parent, title):
            wx.Frame.__init__(self, parent, title=title, size=(200, 100))
            self.control = wx.TextCtrl(self, style=wx.TE_MULTILINE)
    
            # Create Statusbar
            self.CreateStatusBar()
    
            # Set up the menus
            filemenu = wx.Menu()
            infomenu = wx.Menu()
    
            # file menu
            filemenu.Append(wx.ID_NEW, "New") # Id of wx.ID_NEW (5002) which picks up an automatic image
            filemenu.Append(wx.ID_SAVE, "Save")
    
            m1 = wx.MenuItem(filemenu, 100, "Manual Bitmap") #A manual id of 100
            m1.SetBitmap(wx.Bitmap('./myimage1.png'))
            filemenu.AppendItem(m1)
    
            m2 = wx.MenuItem(filemenu, 101, "Manual Bitmap 2") #A manual id of 101
            m2.SetBitmap(wx.Bitmap('./myimage2.png'))
            filemenu.AppendItem(m2)
            #----------------------------------------------#    
            preferences = wx.MenuItem()
            preferences.SetId(102)
            preferences.SetText("Preferences")
            preferences.SetHelp("Preferences Help")
            preferences.SetKind(wx.ITEM_NORMAL)
            gear = wx.Bitmap(os.path.join(os.path.dirname(__file__), 'myimage2.png'))
            preferences.SetBitmap(gear)
            filemenu.AppendItem(preferences)
            #----------------------------------------------#    
            filemenu.AppendSeparator()
    
            filemenu.Append(wx.ID_EXIT, "Exit")
    
            # info menu
            infomenu.Append(wx.ID_ABOUT, "About")
    
            # bind file menu
            self.Bind(wx.EVT_MENU, self.OnManualBitmap, id=100) # Bind to the Id
            self.Bind(wx.EVT_MENU, self.OnManualBitmap, id=101) # Bind to the Id
            self.Bind(wx.EVT_MENU, self.OnManualBitmap, id=102) # Bind to the Id
            self.Bind(wx.EVT_MENU, self.OnExit, id=wx.ID_EXIT)
    
            # Creating the menubar.
            menuBar = wx.MenuBar()
    
            # Add menus
            menuBar.Append(filemenu, "&Preferences")
            menuBar.Append(infomenu, "&Help")
    
            # Add the MenuBar to the Frame content.
            self.SetMenuBar(menuBar)
            self.Show(True)
    
        def OnManualBitmap(self, event):
            print event.EventObject.GetLabel(event.Id)
            print event.Id
    
        def OnExit(self, event):
            self.Destroy()
    
    app = wx.App()
    frame = MainWindow(None, "Menu Image Test")
    app.MainLoop()