user14499424
user14499424

Reputation:

How do I make menu options do different things in WxPython?

I have a problem with my menu in WxPython! In the file header I have 'File' and in that I have 2 options, 'Save' and 'Close'...When I click save, I want it to print "Saved" and when I clock quit, the application should print "Closed" and close...But if I click even save it's closing! So can you please help me. Here is a part of my code:

menubar = wx.MenuBar()
fileMenu = wx.Menu()

menubar.Append ( fileMenu, '&File' )

m1 = fileMenu.Append ( wx.ID_EXIT, 'Save' )
self.Bind ( wx.EVT_MENU, self.OnSave, m1 )

m2 = fileMenu.Append ( wx.ID_EXIT, 'Quit' )
self.Bind ( wx.EVT_MENU, self.OnQuit, m2 )

self.SetMenuBar ( menubar )

And the functions:

def OnSave ( self, event ):
    
    text = self.text_ctrl.GetValue()
    
    fil.write ( text )
    print ( "Saved file")

def OnQuit ( self, event ):
    
    print ( "Closed" )
    self.Close()

Upvotes: 0

Views: 632

Answers (2)

Rolf of Saxony
Rolf of Saxony

Reputation: 22443

You are using the same Id i.e. wx.ID_EXIT for both menu items, which as @Petr Blahos has pointed out, is causing your problem.
There is however an issue with Petr's answer, whilst technically correct,
wx.NewId is now Deprecated and although it still works, it has been replaced by wx.NewIdRef.

wx.NewId()
Generates an integer identifier unique to this run of the program.

Return type
int

Deprecated IDs generated by this function can possibly conflict with IDs used elsewhere in the application code. It is recommended to instead use the wx.ID_ANY ID to assign generated IDs for the controls, menu items and etc. that you create in the application. These IDs are guaranteed to not conflict with the other IDs that are in use in the application. For those cases where you need to create an ID that can be used more than once then please see wx.NewIdRef.

wx.NewIdRef(count=1)
Reserves a new Window ID (or range of WindowIDs) and returns a wx.WindowIDRef object (or list of them) that will help manage the reservation of that ID.

This function is intended to be a drop-in replacement of the old and deprecated wx.NewId function, with the added benefit that the ID should never conflict with an in-use ID or other IDs generated by this function.

wx.NewIdRef also has a count function, so it can be used to grab a group of id's that you use as required. i.e.

>>> myIds = wx.NewIdRef(count=6)
>>> myIds
[WindowIDRef: -31973, WindowIDRef: -31972, WindowIDRef: -31971, WindowIDRef: -31970, WindowIDRef: -31969, WindowIDRef: -31968]
>>> useId = myIds[3].Id
>>> useId
-31970

Note that wx.NewIdRef, wx.ID_ANY and -1 can all be used in this menu context. See this simple example:

import wx

class Test(wx.Frame):

    def __init__(self,parent):
        wx.Frame.__init__(self,parent,title="Frame aka Window",size = (300,200))
        panel = wx.Panel(self)
        self.status=self.CreateStatusBar()
        self.status.SetStatusText("Status bar text")
        menubar=wx.MenuBar()
        firstm=wx.Menu()
        secondm=wx.Menu()

        fm1 = wx.MenuItem(firstm, wx.NewIdRef(), 'New Window\tAlt+N')
        firstm.Append(fm1)
        self.Bind(wx.EVT_MENU, self.OnMenu1, id=fm1.GetId())
        fm2 = wx.MenuItem(firstm, wx.NewIdRef(), 'Open', "Text for the statusbar")
        firstm.Append(fm2)
        self.Bind(wx.EVT_MENU, self.OnMenu2, id=fm2.GetId())
        fm3 = wx.MenuItem(firstm, -1, 'Quit\tAlt+Q')
        firstm.Append(fm3)
        self.Bind(wx.EVT_MENU, self.OnMenu3, id=fm3.GetId())

        sm1 = wx.MenuItem(firstm, wx.ID_ANY, 'Re-Do', "Statusbar Re-Do")
        secondm.Append(sm1)
        self.Bind(wx.EVT_MENU, self.OnsMenu1, id=sm1.GetId())
        sm2 = wx.MenuItem(secondm, wx.ID_ANY, 'Un-Do', "Statusbar Un-Do")
        secondm.Append(sm2)
        self.Bind(wx.EVT_MENU, self.OnsMenu2, id=sm2.GetId())

        menubar.Append(firstm,"File")
        menubar.Append(secondm,"Edit")

        self.SetMenuBar(menubar)

        t = wx.StaticText(panel,-1,"Hello i'm a test", pos=(10,20))

    def OnMenu1(self, event):
        print("Menu item 1",event.GetId())

    def OnMenu2(self, event):
        print("Menu item 2",event.GetId())
        
    def OnMenu3(self, event):
        print("Menu item 3 Quit",event.GetId())
        self.Destroy()
                
    def OnsMenu1(self, event):
        print("2nd Menu item 1",event.GetId())

    def OnsMenu2(self, event):
        print("2nd Menu item 2",event.GetId())

if __name__=='__main__':
    app=wx.App()
    frame=Test(None)
    frame.Show()
    app.MainLoop()

Upvotes: 1

Petr Blahos
Petr Blahos

Reputation: 2433

The first parameter of fileMenu.Append is important. It is used to tell one menu item from the other one, but you used the same value for both.

    m1 = fileMenu.Append(wx.ID_SAVE, 'Save')
    self.Bind(wx.EVT_MENU, self.OnSave, m1)
    
    m2 = fileMenu.Append(wx.ID_EXIT, 'Quit')
    self.Bind(wx.EVT_MENU, self.OnQuit, m2)

In my programs I prefer getting a free id from system, using wx.NewId(). If you have these "stock" menu entries, ID_SAVE and ID_EXIT make perfect sense, but if you make your own entries, you can do:

    m3 = fileMenu.Append(wx.NewId(), 'My own menu item')
    self.Bind(wx.EVT_MENU, self.OnMyOwnFunction, m3)
    m4 = fileMenu.Append (wx.NewId(), 'Another menu item')
    self.Bind(wx.EVT_MENU, self.OnAnotherFunction, m4)

Upvotes: 0

Related Questions