I am trying to programmatically create and bind a table of accelerators in wxPython in a loop so that I don’t need to worry about getting and assigning new IDs to each accelerators (and with a view to inhaling the handler list from some external resource, rather than hard-coding them). I also pass in some arguments to the handler via a lambda since a lot of my handlers will be the same but with different parameters (move, zoom, etc).
The class is subclassed from wx.Frame and setup_accelerators() is called during initialisation.
def setup_accelerators(self):
bindings = [
(wx.ACCEL_CTRL, wx.WXK_UP, self.on_move, 'up'),
(wx.ACCEL_CTRL, wx.WXK_DOWN, self.on_move, 'down'),
(wx.ACCEL_CTRL, wx.WXK_LEFT, self.on_move, 'left'),
(wx.ACCEL_CTRL, wx.WXK_RIGHT, self.on_move, 'right'),
]
accelEntries = []
for binding in bindings:
eventId = wx.NewId()
accelEntries.append( (binding[0], binding[1], eventId) )
self.Bind(wx.EVT_MENU, lambda event: binding[2](event, binding[3]), id=eventId)
accelTable = wx.AcceleratorTable(accelEntries)
self.SetAcceleratorTable(accelTable)
def on_move(self, e, direction):
print direction
However, this appears to bind all the accelerators to the last entry, so that Ctrl+Up prints "right", as do all the other three. How to correctly bind multiple handlers in this way?
Got it. the problem was you weren’t passing in your direction as an argument to your lambda (it was only looking at the event argument (and self) because that was all your lambda was defined as accepting) This page gave me the help I needed to get this working (here is a gist):
My original answer (which is an acceptable alternate solution) is: