this is my first question on StackOverFlow.
Python version: 3.6.1, wxPython version: 4.0.1, OS: Windows 10, 64 bits.
I have been exploring wxPython for a scientific project. I need to generate sliders on the fly. This I can do along with StaticText elements to display the current value of the xth slider position. I have a function "CreateSliderFun" that returns a handler function. I bind the xth handler function to the xth slider widget. I would expect everything to be fine, but a typeerror occurs:
TypeError: fun() missing 1 required positional argument: 'e'
If i provide the hardcoded_fun the first added slider works as expected. Any extra sliders will be linked to the first generated StaticText element.
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()
Your CreateSliderFun returns a function, that takes 2 parameters: self and e. You need this:
def CreateSliderFun(self, i):
def fun(e):
....
You may consider not making handler on the fly, but doing
self.Bind(wx.EVT_SCROLL, self.common_handler)
and
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?