【问题标题】:Best way to get the name of a button that called an event?获取调用事件的按钮名称的最佳方法?
【发布时间】:2010-11-01 20:40:22
【问题描述】:

在以下代码中(受this sn-p 启发),我使用单个事件处理程序buttonClick 来更改窗口的标题。目前,我需要评估事件的 Id 是否对应于按钮的 Id。如果我决定添加 50 个按钮而不是 2 个,这种方法可能会变得很麻烦。有没有更好的方法来做到这一点?

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()

【问题讨论】:

    标签: python user-interface events event-handling wxpython


    【解决方案1】:

    保留一个dict,其中的键是按钮的.Id,值是按钮名称或其他内容,因此您可以在buttonClick 中进行单个dict 查找而不是长if/elif 链.

    代码sn-ps:在__init__中,添加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)
    

    等等 50 个按钮(或其他)[它们可能最好在循环中创建,顺便说一句;-)]。 所以buttonClick变成了:

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

    【讨论】:

      【解决方案2】:

      您可以创建一个按钮字典,并根据id 进行外观...类似这样:

      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)
      

      【讨论】:

        【解决方案3】:

        我遇到了类似的问题:我正在根据用户提供的数据生成按钮,并且我需要这些按钮来影响另一个类,因此我需要传递有关 buttonclick 的信息。我所做的是为我生成的每个按钮显式分配按钮 ID,然后将有关它们的信息存储在字典中以供以后查找。

        我原以为会有一种更漂亮的方法来做到这一点,构建一个传递更多信息的自定义事件,但我所看到的只是字典查找方法。此外,我保留了一个按钮列表,以便在需要时将它们全部删除。

        下面是一个经过轻微修改的类似代码示例:

        self.buttonDefs = {}
        self.buttons = []
        id_increment = 800
        if (row, col) in self.items:
            for ev in self.items[(row, col)]:
                id_increment += 1
                #### Populate a dict with the event information
                self.buttonDefs[id_increment ] = (row, col, ev['user'])
                ####
                tempBtn = wx.Button(self.sidebar, id_increment , "Choose",
                                    (0,50+len(self.buttons)*40), (50,20) )
                self.sidebar.Bind(wx.EVT_BUTTON, self.OnShiftClick, tempBtn)
                self.buttons.append(tempBtn)
        
        def OnShiftClick(self, evt):
            ### Lookup the information from the dict
            row, col, user = self.buttonDefs[evt.GetId()]
            self.WriteToCell(row, col, user)
            self.DrawShiftPicker(row, col)
        

        【讨论】:

          【解决方案4】:

          您可以给按钮一个名称,然后在事件处理程序中查看名称。

          当你制作按钮时

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

          当按钮被点击时:

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

          【讨论】:

          • 当我想不出更好的方法时,我也经常在小部件上设置属性。
          【解决方案5】:

          我建议您使用不同的事件处理程序来处理来自每个按钮的事件。如果有很多共同点,您可以将它们组合成一个函数,该函数返回一个具有您想要的特定行为的函数,例如:

          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"
          

          【讨论】:

          • 哇,我认为这是一种比字典查找方法更好的方法。这样,当您可能只使用一个条目时,您就不会填充 dict
          【解决方案6】:

          充分利用 Python 等语言的优势。您可以将额外的参数传递给您的事件回调函数,就像这样。

          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
          

          当然,参数可以是任何你想要的。

          【讨论】:

          • 不错的方法和使用很酷的 Python 新功能(无论如何,2.5 对我来说是新的)。我会经常使用lambda 版本,尽管functools.partail 肯定更清晰,并且没有麻烦的名称绑定问题。
          【解决方案7】:

          我需要做同样的事情来跟踪按钮按下。我使用 lambda 函数绑定到事件。这样我就可以将整个按钮对象传递给事件处理函数以进行相应的操作。

              class PlatGridderTop(wx.Frame):
                  numbuttons = 0
                  buttonlist = []
          
          
                  def create_another_button(self, event): # wxGlade: PlateGridderTop.<event_handler>
                          buttoncreator_id = wx.ID_ANY
                          butonname = "button" + str(buttoncreator_id)
                          PlateGridderTop.numbuttons = PlateGridderTop.numbuttons + 1
                          thisbutton_number = PlateGridderTop.numbuttons
          
                          self.buttonname  =  wx.Button(self,buttoncreator_id ,"ChildButton %s" % thisbutton_number )
                          self.Bind(wx.EVT_BUTTON,lambda event, buttonpressed=self.buttonname: self.print_button_press(event,buttonpressed),self.buttonname)
                          self.buttonlist.append(self.buttonname)
                          self.__do_layout()
                          print "Clicked plate button %s" % butonname
                          event.Skip()
                 def print_button_press(self,event,clickerbutton):
                         """Just a dummy method that responds to a button press"""
                         print "Clicked a created button named %s with wxpython ID %s" % (clickerbutton.GetLabel(),event.GetId())
          

          免责声明:这是我在 stackoverflow 上的第一篇文章

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2010-09-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-09-04
            相关资源
            最近更新 更多