When the start timer is called by the button click, how is it that the lines following the count_down function call are executed immediately before the counter is completed and returned?

Also, if we double click the start button it behaves weirdly.

Please explain the program flow in event-driven programs in python.

from tkinter import *
import math

def start_timer():

    work_sec = 15
    count_down(work_sec)
    timer_label.config(text="Work", fg="red")
    print("Debug")


def count_down(count):

    count_min = math.floor(count/60)
    count_sec = count % 60

    canvas.itemconfig(timer_text, text=f"{count_min}:{count_sec}")
    if count > 0:
        window.after(1000, count_down, count-1)



window = Tk()

timer_label = Label(text="Timer", fg="green", font=("Courier", 48, "bold"))
timer_label.pack()

canvas = Canvas(width=300, height=250, bg="black")
timer_text = canvas.create_text(150, 125, text="00:00", fill="white", font=("Arial", 35))
canvas.pack()

start_button = Button(text="start", command=start_timer)
start_button.pack()

window.mainloop()
1

There are 1 best solutions below

0
On

The point of tk.after is that it doesn't freeze the GUI. In the code count_down updates the count and the canvas and then returns to keep the GUI responsive. In the code below I've added some print statements which show what's being called when in the console. I hope this makes the sequence of calls more obvious. Try clicking the 'start' button more than once a few seconds apart.

import tkinter as tk
from math import floor

start_timer_count = 0

def start_timer():
    global start_timer_count
    start_timer_count += 1
    print( f"start_timer_called for {start_timer_count} th time."  )
    work_sec = 15
    count_down(work_sec, start_timer_count )
    print("start_completes")


def count_down(count, start_count ):

    print( f"count_down called. count = {count}. Called by start_timer {start_count}." )
    count_min = floor(count/60)
    count_sec = count % 60

    canvas.itemconfig(timer_text, text=f"{count_min}:{count_sec}")
    if count > 0:
        window.after(1000, count_down, count-1, start_count )



window = tk.Tk()

timer_label = tk.Label(text="Timer", fg="green", font=("Courier", 48, "bold"))
timer_label.pack()

canvas = tk.Canvas(width=300, height=250, bg="black")
timer_text = canvas.create_text(150, 125, text="00:00", fill="white", font=("Arial", 35))
canvas.pack()

start_button = tk.Button(text="start", command=start_timer)
start_button.pack()

window.mainloop()