How can I prevent my program from freezing in tkinter when using the after() function?

61 Views Asked by At
import ttkbootstrap as tb


def timer():
    global hours, minutes, seconds
    hours = 0
    minutes = 0
    seconds = 0

    if hours_combo.get() != "":
        hours = hours_combo.get()
        hours = int(hours)
        
    if minutes_combo.get() != "":
        minutes = minutes_combo.get()
        minutes = int(minutes)
        
    if seconds_combo.get() != "":
        seconds = seconds_combo.get()
        seconds = int(seconds)
    
    root.after(((1000 * ((hours * 3600) + (minutes * 60) + seconds))), finish)
    countdown()

def countdown():
    for count in range(seconds, 0, -1):
        countdown_seconds = count % 60
        countdown_minutes = int(count / 60) % 60
        countdown_hours = int(count / 3600)
        print(f"{countdown_hours:02}:{countdown_minutes:02}:{countdown_seconds:02}")
        root.after(1000)

def finish():
    print("Done")

When I called the countdown function, the program executes correctly and the countdown prints but the Gui freezes. I thought previously that the after() function prevented this from happening. I removed the variable declarations as they aren't relevant. I attempted to use multiprocessing or threading but neither solution worked.

1

There are 1 best solutions below

0
On BEST ANSWER

Here is how you use after to perform this task. You have after call that same function one second later, until the counter goes to zero. Remember that your event callbacks must run VERY quickly. You can't ever delay in an event callback.


seconds = 0
def timer():
    global seconds
    hours = 0
    minutes = 0
    seconds = 0

    if hours_combo.get() != "":
        hours = hours_combo.get()
        hours = int(hours)
        
    if minutes_combo.get() != "":
        minutes = minutes_combo.get()
        minutes = int(minutes)
        
    if seconds_combo.get() != "":
        seconds = seconds_combo.get()
        seconds = int(seconds)

    seconds = hours*3600 + minutes*60 + seconds
    
    countdown()

def countdown():
    global seconds
    seconds -= 1
    countdown_seconds = seconds % 60
    countdown_minutes = seconds // 60 % 60
    countdown_hours = seconds // 3600
    print(f"{countdown_hours:02}:{countdown_minutes:02}:{countdown_seconds:02}")

    if seconds:
        root.after(1000, countdown)
    else:
        print("Done")