Best way to get the name of a button that called an event?

12,174

Solution 1

You could give the button a name, and then look at the name in the event handler.

When you make the button

b = wx.Button(self, 10, "Default Button", (20, 20))
b.myname = "default button"
self.Bind(wx.EVT_BUTTON, self.OnClick, b)

When the button is clicked:

def OnClick(self, event):
    name = event.GetEventObject().myname

Solution 2

Take advantage of what you can do in a language like Python. You can pass extra arguments to your event callback function, like so.

import functools

def __init__(self):
    # ...
    for i in range(10):
        name = 'Button %d' % i
        button = wx.Button(parent, -1, name)
        func = functools.partial(self.on_button, name=name)
        button.Bind(wx.EVT_BUTTON, func)
    # ...

def on_button(self, event, name):
    print '%s clicked' % name

Of course, the arguments can be anything you want.

Solution 3

I recommend that you use different event handlers to handle events from each button. If there is a lot of commonality, you can combine that into a function which returns a function with the specific behavior you want, for instance:

def goingTo(self, where):
    def goingToHandler(event):
        self.SetTitle("I'm going to " + where)
    return goingToHandler

def __init__(self):
    buttonA.Bind(wx.EVT_BUTTON, self.goingTo("work"))
    # clicking will say "I'm going to work"
    buttonB.Bind(wx.EVT_BUTTON, self.goingTo("home"))
    # clicking will say "I'm going to home"

Solution 4

Keep a dict with keys that are the .Id of the buttons and values that are the button names or whatever, so instead of a long if/elif chain you do a single dict lookup in buttonClick.

Code snippets: in __init__, add creation and update of the dict:

self.panel1 = wx.Panel(self, -1)
self.thebuttons = dict()

self.button1 = wx.Button(self.panel1, id=-1,
    pos=(10, 20), size = (20,20))
self.thebuttons[self.button1.Id] = 'Button 1'
self.button1.Bind(wx.EVT_BUTTON, self.buttonClick)

and so on for 50 buttons (or whatever) [they might be better created in a loop, btw;-)]. So buttonClick becomes:

   def buttonClick(self,event):
       button_name = self.thebuttons.get(event.Id, '?No button?')
       self.setTitle(button_name + ' clicked')

Solution 5

You could create a dictionary of buttons, and do the look based on the id ... something like this:

class MyFrame(wx.Frame):
   def _add_button (self, *args):
      btn = wx.Button (*args)
      btn.Bind (wx.EVT_BUTTON, self.buttonClick)
      self.buttons[btn.id] = btn
   def __init__ (self):
      self.button = dict ()
      self._add_button (self.panel1, id=-1,
        pos=(10, 20), size = (20,20))

    self._add_button = (self.panel1, id=-1,
        pos=(40, 20), size = (20,20))

    self.Show (True)

   def buttonClick(self,event):
      self.SetTitle (self.buttons[event.Id].label)
Share:
12,174
JcMaco
Author by

JcMaco

Updated on June 04, 2022

Comments

  • JcMaco
    JcMaco almost 2 years

    In the following code (inspired by this snippet), I use a single event handler buttonClick to change the title of the window. Currently, I need to evaluate if the Id of the event corresponds to the Id of the button. If I decide to add 50 buttons instead of 2, this method could become cumbersome. Is there a better way to do this?

    import wx
    
    class MyFrame(wx.Frame):
        def __init__(self):
            wx.Frame.__init__(self, None, wx.ID_ANY, 'wxBitmapButton',
                pos=(300, 150), size=(300, 350))
            self.panel1 = wx.Panel(self, -1)
    
            self.button1 = wx.Button(self.panel1, id=-1,
                pos=(10, 20), size = (20,20))
            self.button1.Bind(wx.EVT_BUTTON, self.buttonClick)
    
            self.button2 = wx.Button(self.panel1, id=-1,
                pos=(40, 20), size = (20,20))
            self.button2.Bind(wx.EVT_BUTTON, self.buttonClick)
    
            self.Show(True)
    
        def buttonClick(self,event):
            if event.Id == self.button1.Id:
                self.SetTitle("Button 1 clicked")
            elif event.Id == self.button2.Id:
                self.SetTitle("Button 2 clicked")            
    
    application = wx.PySimpleApp()
    window = MyFrame()
    application.MainLoop()
    
  • FogleBird
    FogleBird almost 15 years
    I often set attributes on widgets as well when I can't think of a better way.
  • tom10
    tom10 almost 15 years
    Nice approach and use of cool new Python functionality (2.5 is new for me anyway). I would often do the lambda version of this, though functools.partail is certainly more clear and without the troublesome name binding issues.
  • dw1
    dw1 about 2 years
    Could do name = event.GetEventObject().GetLabel(). Thanks for showing the GetEventObject() function!