Search code examples
pythonsliderplayback

wxPython - Play slider


I have a slider in the application and the panel on which are displayed something based on the value of the slider. I made a function (call by pressing button) that moves the slider by one increment at a time, but it does not work because the OnSliderDraw function is not called. Function is called when I move the slider manually, using the mouse, but I would like using PlaySlider function.

self.Bind(wx.EVT_BUTTON, self.PlaySlider, id=xrc.XRCID("m_buttonPlay"))
self.Slider2 = xrc.XRCCTRL(self, "m_slider3")
self.Bind(wx.EVT_SLIDER, self.OnSliderDraw, id=xrc.XRCID("m_slider3"))

def OnSliderDraw(self, event):
.
.
. something
.
.

def PlaySlider(self, event):
    for i in range(0, self.Slider2.GetMax()):
        self.Slider2.SetValue(i+1)
        time.sleep(0.04)

Solution

  • If all you want to to is update the slider, try this:

    ## NOTE: This is untested
    def SliderDrawer(self):
        for i in range(0,self.Slider2.GetMax()):
            self.Slider2.SetValue(i+1)
            wx.Yield() ## Added the Yield function
            time.sleep(0.1) ## Increased time so that visual can be seen
    
    def PlaySlider(self,event):
        wx.CallAfter(self.SliderDrawer)
        event.Skip()
    

    One of the issues you have is that you are not letting the User Interface update itself. While the event is going on there will be a lock in place until the event has finished.

    This can be worked around by calling a separate function after the event. And within that separate function use wx.Yield() to allow the UI to update itself.

    Also, if your SliderDraw function was going to do something else, you should include something more descriptive than ...something... because that something may be important ;)

    EDIT:

    If I may have misunderstood your question, and all you want to do is call the OnSlideDraw function, then you could use the idea of using wx.Yield() in your loop to see if it will be called, or modify OnSliderDraw to not be an event, but something that is called during your loop:

    self.Bind(wx.EVT_BUTTON, self.PlaySlider, id=xrc.XRCID("m_buttonPlay"))
    # Removed
    #self.Slider2 = xrc.XRCCTRL(self, "m_slider3")
    self.Bind(wx.EVT_SLIDER, self.OnSliderDraw, id=xrc.XRCID("m_slider3"))
    
    def OnSliderDraw(self):
    .
    .
    . something
    .
    .
    
    def PlaySlider(self, event):
        for i in range(0, self.Slider2.GetMax()):
            self.Slider2.SetValue(i+1)
            self.OnSliderDraw()
            wx.Yield() # Added the Yield
            time.sleep(0.1) # Increased Time
        event.Skip() # It's important to finish the event with a Skip() to prevent any cross event phenomenon. 
    

    In your OnSliderDraw you can then do what you wanted to do without having to reference the event, and instead work directly with the widgets.