How to Properly Use Wx. Calllater in Wx. Python

I want to loop and call a function every 1000 milliseconds with wx.CallLater. I implemented this (see below), but it does not factor in the delay - it seems to execute automatically. How can I get this to wait 1000 milliseconds between function calls?

This function is within a class. In my main module, I instantiate an object of this class and call the task_loop function. I intend to keep the loop going until will_break is set to True, and task_loop returns the work_session_agenda in the main module. Thank you for your help!

def task_loop(self, duration, window, task, work_session_agenda, start, completed):

    will_break = False
    will_continue = False

    duration -= datetime.timedelta(seconds=1)

More code in here - which, depending on conditionals, sets the values of will_break and will_continue

    if will_break:
        print('BREAKING')
        return work_session_agenda
    else:
        print('GOT HERE')
        timer = wx.CallLater(1000, self.task_loop, duration, window, task, work_session_agenda, start, completed)
4

1 Answer

Below you can find an example with wx.CallLater and with wx.Timer as suggested in the comments. Notice that in both cases the GUI remains responsive during the waiting time.

With wx.Timer

import wx
import time

class MyFrame(wx.Frame):
    def __init__(self):
        super().__init__(None, title="With wx.Timer", size=(500,500))

        #### Variables
        self.will_continue = True
        self.i = 0
        self.total = 5
        self.mili = 1000

        #### Widgets
        # Parent panel
        self.panel = wx.Panel(self)
        # Button
        self.button  = wx.Button(self.panel, label="Start", pos=(50, 50))
        self.button2 = wx.Button(self.panel, label="Button", pos=(50 ,100))

        #### Timer Notice that wx.Timer is own by the frame itself
        self.timer = wx.Timer(self)

        #### Bind
        self.button.Bind(wx.EVT_BUTTON, self.OnStart)
        self.Bind(wx.EVT_TIMER, self.OnCheck, self.timer)

    def OnStart(self, event):
        ## OnStart, disable the button and change its label and start the timer.
        ## Notice with Button that the GUI remain responsive
        ## while the timer runs
        if self.will_continue:
            print(self.i)
            print(time.ctime())
            self.button.SetLabel("Running")
            self.button.Disable()
            self.timer.Start(self.mili)
        ## When finish waiting reset everything so the start button can run 
        ## again and stop the timer
        else:
            self.timer.Stop()
            self.button.SetLabel("Start")
            self.button.Enable()
            self.will_continue = True
            self.i = 0            

    def OnCheck(self, event):
        self.i += 1 
        if self.i > self.total:
            self.will_continue = False
        else:
            pass
        self.OnStart(event)


# Run the program
if __name__ == "__main__":
    app = wx.App()
    frame = MyFrame()
    frame.Show()
    app.MainLoop()

With wx.CallLater

import wx
import time

class MyFrame(wx.Frame):
    def __init__(self):
        super().__init__(None, title="With wx.CallAfter", size=(500,500))

        #### Variables
        self.will_continue = True
        self.i = 0
        self.total = 5
        self.mili = 1000

        #### Widgets
        # Parent panel
        self.panel = wx.Panel(self)
        # Button
        self.button  = wx.Button(self.panel, label="Start", pos=(50, 50))
        self.button2 = wx.Button(self.panel, label="Button", pos=(50 ,100))

        #### Bind
        self.button.Bind(wx.EVT_BUTTON, self.OnStart)

    def OnStart(self, event):
        ## OnStart, disable the button and change its label and make the 
        ## wx.CallLater call. Notice with Button that the GUI remain responsive
        ## while wx.CallLater waits
        if self.will_continue:
            print(self.i)
            print(time.ctime())
            self.button.SetLabel("Running")
            self.button.Disable()
            wx.CallLater(self.mili, self.OnCheck, event)
        ## When finish waiting reset everything so the start button can run 
        ## again
        else:
            self.button.SetLabel("Start")
            self.button.Enable()
            self.will_continue = True
            self.i = 0            

    def OnCheck(self, event):
        self.i += 1 
        if self.i > self.total:
            self.will_continue = False
        else:
            pass
        self.OnStart(event)


# Run the program
if __name__ == "__main__":
    app = wx.App()
    frame = MyFrame()
    frame.Show()
    app.MainLoop()

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

David Miller

David Miller

Executive Financial & Market Analyst

David Miller brings 15 years of experience in global economics, personal finance strategy, and market dynamics. He specializes in turning complex economic trends into actionable insights for everyday readers.

Share this article
Twitter Facebook Pinterest