BobbyDobby
BobbyDobby

Reputation: 41

How do I make the countdown display in a countdown timer

I am new to Python and just programming in general. I need help to create a countdown display to my timer which is a tequila timer. My friends drink a lot of Tequila and asked me to make them a timer, because they know nothing about computers.

Anyways, I have made the layout the best way I could do it and it looks like this: https://i.sstatic.net/bvt57.png

What I need help with is that when the 1 minute button is clicked, it counts down from one minute to 0. And the same goes with the other button. I also need help with the stop ruction, so you can stop the timer at any time by pressing the stop button. It would really be a big help!!

Here is my code:

import tkinter as tk

#GUI
root = tk.Tk()
root.title("Tequila timer")

#Load of background with the tequila bottle
canvas = tk.Canvas(root, width=423, height=700)
canvas.pack()
Load = tk.PhotoImage(file="tequila.png")
canvas.create_image(211, 350, image=Load)

#buttons
btn_1min = tk.Button(root, text="1 min", width=10, height=5, command=root.quit)
btn_1min_v = canvas.create_window(140, 350, window=btn_1min)

btn_10min = tk.Button(root, text="10 min", width=10, height=5, command=root.quit)
bt1_10min_v = canvas.create_window(283, 350, window=btn_10min)

btn_1hour = tk.Button(root, text="1 hour", width=10, height=5, command=root.quit)
bt1_1hour_v = canvas.create_window(140, 475, window=btn_1hour)

btn_2hours = tk.Button(root, text="2 hours", width=10, height=5, command=root.quit)
bt1_2hours_v = canvas.create_window(283, 475, window=btn_2hours)

btn_stop = tk.Button(root, text="Stop", width=10, height=5, command=root.quit)
bt1_stop_v = canvas.create_window(211, 600, window=btn_stop)

#Display
label = tk.Label(root, text="00:00:00", width=9, font=("calibri", 40, "bold"))
label.pack()
label_v = canvas.create_window(211, 200, window=label)

root.mainloop()

Upvotes: 1

Views: 318

Answers (1)

Axe319
Axe319

Reputation: 4365

The problem is none of your buttons are mapped to anything. Well, other than root.quit which just closes your window.

So lets start with your first problem. You need to update the text in your Label. A good way to do that is with tkinters StringVar class. Updating a StringVar will also update the text in your Label so lets do that first.

countdown = tk.StringVar()
countdown.set("00:00:00")

and then set it as the text in your Label.

label = tk.Label(root, textvariable=countdown, width=9, font=("calibri", 40, "bold"))

Now that that's taken care of. lets move on to your second problem. Your lack of call back functions. First lets set us up with a function to call that accepts a variable amount of seconds to count down from.

To display something after root.mainloop() has been called we can use the after() method. It will return an identifier that we can use to cancel the update later. However, in order to use it in another function later to cancel, we should make it a global variable with the keyword global.

The root.after takes a milliseconds argument and a function to call after those milliseconds have elapsed. Lets call this function again with one fewer milliseconds than it was called with. also, if the seconds have dipped below 0 we should cancel the callback.

We can do that with root.after_cancel and handing it the after identifier we retrieved from root.after before.

Another thing to note is that root.afters function argument expects a function object. To hand it a function with an argument we can wrap it in a lambda.

def update(seconds):
    global after
    if seconds >= 0:
        countdown.set(seconds_to_time(seconds))
        after = root.after(1000, lambda: update(seconds - 1))
    else:
        root.after_cancel(after)

But what is this seconds_to_time function were setting our StringVar to? Well, it's just a little helper to make our seconds display in a proper hh:mm:ss format.

def seconds_to_time(seconds):
    hours = seconds // 3600
    seconds -= hours * 3600
    minutes = seconds // 60
    seconds -= minutes * 60
    return f'{hours:02d}:{minutes:02d}:{seconds:02d}'

And your final request is to stop the countdown. We can do that by just cancelling our global after identifier. It's a good idea to make sure we've set the after first by avoiding NameError errors in case it hasn't been set yet.

def stop():
    try:
        root.after_cancel(after)
    except NameError:
        pass

Full code below: note the callback functions for your buttons are wrapped in lambdas to allow us to hand an argument to the callback.

import tkinter as tk

def update(seconds):
    global after
    if seconds >= 0:
        countdown.set(seconds_to_time(seconds))
        after = root.after(1000, lambda: update(seconds - 1))
    else:
        root.after_cancel(after)

def seconds_to_time(seconds):
    hours = seconds // 3600
    seconds -= hours * 3600
    minutes = seconds // 60
    seconds -= minutes * 60
    return f'{hours:02d}:{minutes:02d}:{seconds:02d}'

def stop():
    try:
        root.after_cancel(after)
    except NameError:
        pass


#GUI
root = tk.Tk()
root.title("Tequila timer")

#Load of background with the tequila bottle
canvas = tk.Canvas(root, width=423, height=700)
canvas.pack()
Load = tk.PhotoImage(file="tequila.png")
canvas.create_image(211, 350, image=Load)

countdown = tk.StringVar()
countdown.set("00:00:00")

#buttons
btn_1min = tk.Button(root, text="1 min", width=10, height=5, command=lambda: update(60))
btn_1min_v = canvas.create_window(140, 350, window=btn_1min)

btn_10min = tk.Button(root, text="10 min", width=10, height=5, command=lambda: update(600))
bt1_10min_v = canvas.create_window(283, 350, window=btn_10min)

btn_1hour = tk.Button(root, text="1 hour", width=10, height=5, command=lambda: update(3600))
bt1_1hour_v = canvas.create_window(140, 475, window=btn_1hour)

btn_2hours = tk.Button(root, text="2 hours", width=10, height=5, command=lambda: update(7200))
bt1_2hours_v = canvas.create_window(283, 475, window=btn_2hours)

btn_stop = tk.Button(root, text="Stop", width=10, height=5, command=stop)
bt1_stop_v = canvas.create_window(211, 600, window=btn_stop)

#Display
label = tk.Label(root, textvariable=countdown, width=9, font=("calibri", 40, "bold"))
label.pack()
label_v = canvas.create_window(211, 200, window=label)

root.mainloop()

Upvotes: 2

Related Questions