Search code examples
pythoneventsevent-handlingsliderwxpython

wxpython wx.Slider: how to fire an event only if a user pauses for some predetermined time


I have a wx.Slider widget that is bound to an event handler. As a user moves the slider, some process will run. However, because the process can take up to 3 seconds to run, I don't want the event to fire continuously as the user moves the slider. Instead, I want the event to fire only if the user stops moving the slider for some amount of time (say, 2 seconds). I tried using time.time() with a while-loop (see code below), but it didn't work because the event would still fire repeatedly -- it's just that the firing got delayed. Any idea/pointer/suggestion would be greatly appreciated.

import wx
import time

class Example(wx.Frame):

    def __init__(self, *args, **kw):
        super(Example, self).__init__(*args, **kw) 
        self.InitUI()

    def InitUI(self):   
        pnl = wx.Panel(self)
        sld = wx.Slider(pnl, value=200, minValue=150, maxValue=500, pos=(20, 20), 
                        size=(250, -1), style=wx.SL_HORIZONTAL)        
        self.counter = 0
        sld.Bind(wx.EVT_SCROLL, self.OnSliderScroll)

        self.txt = wx.StaticText(pnl, label='200', pos=(20, 90))               

        self.SetSize((290, 200))
        self.SetTitle('wx.Slider')
        self.Centre()
        self.Show(True)    

    def OnSliderScroll(self, e):        
        now = time.time()
        future = now + 2
        while time.time() < future:
            pass
        #substitute for the actual process.
        self.counter += 1
        print self.counter


def main():    
    ex = wx.App()
    Example(None)
    ex.MainLoop()    

if __name__ == '__main__':
    main()   

Solution

  • Delaying with time.sleep will block your GUI. Use wx.CallLater instead, which in the sample below will trigger the delayed event until it has been restarted again.

        def InitUi(self):
            # ...
    
            # Add a delay timer, set it up and stop it
            self.delay_slider_evt = wx.CallLater(2000, self.delayed_event)
            self.delay_slider_evt.Stop()
    
        def OnSliderScroll(self, e):
            # if delay timer does not run, start it, either restart it
            if not self.delay_slider_evt.IsRunning():
                self.delay_slider_evt.Start(2000)
            else:
                self.delay_slider_evt.Restart(2000)
    
        def delayed_event(self):
            #substitute for the actual delayed process.
            self.counter += 1
            print self.counter