wxPython - 动态生成处理函数

时间:2018-04-11 07:46:06

标签: python-3.x wxpython

这是我在StackOverFlow上的第一个问题。

Python版本:3.6.1,wxPython版本:4.0.1,操作系统:Windows 10,64位。

我一直在为一个科学项目探索wxPython。我需要动态生成滑块。这个我可以和StaticText元素一起显示第x个滑块位置的当前值。我有一个函数“CreateSliderFun”,它返回一个处理函数。我将xth处理函数绑定到第x个滑块小部件。我希望一切都很好,但会发生类型错误:

TypeError: fun() missing 1 required positional argument: 'e'

如果我提供hardcoded_fun,则第一个添加的滑块按预期工作。任何额外的滑块都将链接到第一个生成的StaticText元素。

Picture of app and errors.

import wx

def main():
  app = wx.App(redirect=False)
  frame = MyApp(None, 'Hello World!')
  frame.Show(True)
  app.MainLoop()

class MyApp(wx.Frame):
    def __init__(self, parent, title):
      wx.Frame.__init__(self, parent, title=title, pos=(0,0), size=(400,600))

      self.panel = wx.Panel(self, pos=(0,0), size=wx.Size(400,600))

      self.AddSliderButton = wx.Button(self.panel, -1, "AddSlider", size=(80,20), pos=(120,80))
      self.AddSliderButton.Bind(wx.EVT_BUTTON, self.AddSliderHandler)

      self.sld = wx.Slider(self.panel, value=200,
        minValue=200-100,
        maxValue=200+100,
        pos=(60, 10),
        size=(250, -1), style=wx.SL_HORIZONTAL)

      self.txt = wx.StaticText(self.panel, label='200', pos=(20, 10))
      self.sld.Bind(wx.EVT_SCROLL, self.OnSliderScroll)

      self.AddSliderButton = wx.Button(self.panel, -1, "AddSlider", size=(80,20), pos=(120,80))
      self.AddSliderButton.Bind(wx.EVT_BUTTON, self.AddSliderHandler)

      self.statusbar = self.CreateStatusBar()
      self.statusbar.SetStatusText("Moin")

      self.ms = ManySliders(self.panel)

    def OnSliderScroll(self, e):
      obj = e.GetEventObject()
      val = obj.GetValue()
      self.txt.SetLabel(str(val))

    def AddSliderHandler(self, event):
      self.ms.AddSlider()
      self.statusbar.SetStatusText("Added slider number " + str(self.ms.NumberOfSliders))

class ManySliders:
  def __init__(self, controlpanel ):
    self.controlpanel = controlpanel
    self.txts = []
    self.sliders = []
    self.SliderFun = []
    self.size = (250, -1)
    self.style = wx.SL_HORIZONTAL
    self.NumberOfSliders = 0
  def AddSlider(self):
    i = self.NumberOfSliders
    txt = wx.StaticText(self.controlpanel, label=str(self.NumberOfSliders), pos=(20, 120 + i*20))
    self.txts.append(txt)
    sld = wx.Slider(self.controlpanel, value=self.NumberOfSliders,
      minValue=self.NumberOfSliders-100,
      maxValue=self.NumberOfSliders+100,
      pos=(60, 120+i*20),
      size=self.size, style=self.style)
    self.sliders.append(sld)
    sliderfun = self.CreateSliderFun(self.NumberOfSliders)
    self.SliderFun.append(sliderfun)
    self.sliders[i].Bind(wx.EVT_SCROLL, self.SliderFun[i])
    self.NumberOfSliders += 1

  def hardcoded_fun(self, e):
    """ if self.SliderFun[i] is replaced by hardcoded_fun, the first added slider will work,
    and all extra sliders added will be linked to the first created StaticText element
    """
    obj = e.GetEventObject()
    val = obj.GetValue()
    self.txts[0].SetLabel(str(val))

  def CreateSliderFun(self, i):
    def fun(self, e):
      print("but this is never shown due to TypeError: fun() missing 1 required positional argument: 'e'")
      obj = e.GetEventObject()
      val = obj.GetValue()
      self.txts[i].SetLabel(str(val))
    print("we create a new slider function... =",fun)
    return fun

main()

1 个答案:

答案 0 :(得分:1)

您的CreateSliderFun返回一个函数,该函数有2个参数:self和e。你需要这个:

def CreateSliderFun(self, i):
    def fun(e):
        ....

你可以考虑不动态处理,而是做

self.Bind(wx.EVT_SCROLL, self.common_handler)

def common_handler(self, event):
    source = event.GetEventObject() # this is your slider
    txt_widget = self.txts[self.sliders.index(source)] 
    # I did not test it but you get the idea, right?