perimosocordiae
perimosocordiae

Reputation: 17847

wxPython not binding callbacks to events properly

Here's a roughly minimal demonstrative example:

import wx

app = wx.App(False)
frame = wx.Frame(None)

menuBar = wx.MenuBar()
menu = wx.Menu()
menuBar.Append(menu, "&Menu")
frame.SetMenuBar(menuBar)

for name in ['foo','bar','baz']:
    menuitem = menu.Append(-1,"&"+name,name)
    def menuclick(e):
        print(name)
    frame.Bind(wx.EVT_MENU, menuclick, menuitem)

frame.Show(True)
app.MainLoop()

The issue is that every menu item, when clicked, prints "baz". Shouldn't the menuclick function wrap up the appropriate name in its closure and keep the original name around?

Upvotes: 0

Views: 344

Answers (2)

Toni Ruža
Toni Ruža

Reputation: 7512

After the for loop name will be "baz", it's value will not go back in time to when you bound the menuclick to the menu event.

You can get to the menu item name via the event itself like this:

def menuclick(e):
    print(menu.FindItemById(e.Id).Label)

Upvotes: 2

perimosocordiae
perimosocordiae

Reputation: 17847

I found this solution, by I'm not sure why this works where the inner-def version doesn't:

from functools import partial

def onclick(name,e):
    print(name)

for name in ['foo','bar','baz']:
    menuitem = menu.Append(-1,"&"+name,name)
    frame.Bind(wx.EVT_MENU, partial(onclick,name), menuitem)

Upvotes: 0

Related Questions