Search code examples
pythontkintertimer

Display a countdown timer in TKinter while making the code BLOCKING but do not freeze the GUI


Please read my question carefully - I know there are plenty of ways to implement a countdown timer on Tkinter without freezing the window, but all of the existing solutions also cause the code to be non-blocking. For my use case, I need to schedule a task to run automatically after time's up while keeping the GUI active (not frozen). My guess is that I need to somehow block the execution of the next task, but that will also freeze the GUI window. So is there any way out?

What I have so far:

root = Tk.Tk()
def countdown(time, msg='Counting down'):
    def tick():
        nonlocal time
        status(f'{msg} ({60 - time}sec)')
        time += 1
    root.after(1000, tick)

where status() is simply a function that updates the text of some buttons. The current count down function does not work by itself as I don't have a way to stop the after() after the timeout period.

The other parts of the program will be like:

countdown(10)  # I need this line to be blocking or somehow prevents the code from going to next line
print('starting scheduled job...')
job()

I have tried to use threading but as I said earlier on, this causes the code to be non-blocking, and the moment I use Thread.join(), the entire GUI freezes again.


Solution

  • Currently, your question doesn't make a lot of sense to me. From what I understand you want your job() function to be called after the countdown.

    Using thread for this is unnecessary. You can just use after and once the timer reaches 0 call the job() function.

    Here is a minimal example

    import tkinter as tk
    
    
    def job():
        status.config(text="starting job")
    
    
    def countdown(time, msg='Counting down'):
        
        time -= 1
        status.config(text=f'{msg} ({time}sec)')
    
        if time != 0:
            root.after(1000, countdown, time)
    
        else:
            job()  # if job is blocking then create a thread
    
    
    root = tk.Tk()
    
    status = tk.Label(root)
    status.pack()
    
    countdown(20)
    
    root.mainloop()