Reputation: 248
I'm quite new to python programming and I was attempting to create a countdown timer. I wrote down the following code for the timer but it's not working. Can you help in figuring out where the error is? (I did a bit of research on this site and found a few questions relating to timers. In fact most of this code is written based on another answer but I did some changes to it because that code was for a clock and I'm trying to make a timer.)
from tkinter import *
from tkinter import messagebox
class alarmclock():
def __init__(self):
self.alarm = Tk()
self.l0 = Label(self.alarm, text = '----------- Alarm clock 1 -----------')
self.l1 = Label(self.alarm, text = 'Please type in the time:')
self.e0 = Entry(self.alarm)
self.l2 = Label(self.alarm)
self.b0 = Button(self.alarm, text = 'Start countdown', command = lambda: self.timer)
self.l0.grid(row = 0, column = 0, columnspan = 2)
self.l1.grid(row = 1, column = 0, padx = 10, pady =5)
self.e0.grid(row = 1, column = 1, padx = 10)
self.l2.grid(row = 2, column = 1, padx = 10)
self.b0.grid(row = 3, column = 0, columnspan = 2, pady = 5)
self.alarm.mainloop()
def timer(self):
self.b = float(self.e0.get())
self.l2.configure(text = str(self.b))
self.b-=1
if self.b != 0:
self.alarm.after(1000, self.timer)
if self.b == 0:
self.l2.configure(text = str(self.b))
self.messagebox.showwarning('Alarm Clock', 'Time\'s up!')
Upvotes: 0
Views: 267
Reputation: 11
try my timer:
import time
from tkinter import messagebox
class PDTkClock(Exception):
__module__ = Exception.__module__
class Timer:
"""
valid parameter ::--
year, month, week, day, hour, minute, second
"""
_value = ("year", 'month', "week", "day", "hour", "minute", "second")
def __init__(self, tk_widget, **kwargs):
self._sec = 0
self.time_over = False
if self._check(**kwargs) and not self.time_over:
for i in kwargs:
if i == "year":
val = kwargs[i]
self._sec += val * 31556952
elif i == "month":
val = kwargs[i]
self._sec += val * 2628000
elif i == "week":
val = kwargs[i]
self._sec += val * 604800
elif i == "day":
val = kwargs[i]
self._sec += val * 86400
elif i == "hour":
val = kwargs[i]
self._sec += val * 3600
elif i == "minute":
val = kwargs[i]
self._sec += val * 60
elif i == "second":
val = kwargs[i]
self._sec += val * 1
self._time_it(tk_widget, self._sec)
else:
raise PDTkClock(f"kwargs must be {self._value}")
def _time_it(self, tk_widget, sec):
_ = sec
year = sec // 31556952
sec -= year * 31556952
month = sec // 2628000
sec -= month * 2628000
week = sec // 604800
sec -= week * 604800
day = sec // 86400
sec -= day * 86400
hour = sec // 3600
sec -= hour * 3600
minute = sec // 60
sec -= minute * 60
second = sec // 1
get = f"{year}:{month}:{week}:{day}:{hour}:{minute}:{second}"
if _ >=0 and not self.time_over:
tk_widget['text'] = get
tk_widget.update()
tk_widget.after(1000, self._time_it, tk_widget, _ - 1)
else:
messagebox.showwarning('Alarm Clock', 'Time\'s up!')
def _check(self, **kwargs):
ch = []
for i in kwargs:
if i in self._value:
ch.append(True)
else:
ch.append(False)
break
return all(ch)
from tkinter import Tk, Label
r = Tk()
l1 = Label(r)
l1.pack()
Timer(l2, second=10, minute=0)
r.mainloop()
Upvotes: 1
Reputation: 15098
Firstly to answer your main question: tkinter
requires a function that it can call if you press the button, so you have to supply the function so tkinter can call it, here you are are supplying a function with lambda
that returns the function, you can want to call. So when you press the button the lambda function is called and the function(you wanted to call) is returned, but not called. TL;DR, use:
command = lambda: self.timer()
Secondly, the logic is flawed because you are setting the time to self.b
each time the function is ran, instead pass in an argument:
self.b0 = Button(self.alarm,....,command=lambda: self.timer(self.e0.get()))
def timer(self, time):
time = float(time)
self.l2.configure(text=time)
if time > 0:
time -= 1
self.alarm.after(1000, self.timer, time)
else:
self.l2.configure(text=time)
messagebox.showwarning('Alarm Clock', 'Time\'s up!')
Upvotes: 2
Reputation: 799
What about something like this?
from tkinter import *
from tkinter import messagebox
class alarmclock():
def __init__(self):
self.alarm = Tk()
self.l0 = Label(self.alarm, text = '----------- Alarm clock 1 -----------')
self.l1 = Label(self.alarm, text = 'Please type in the time:')
self.e0 = Entry(self.alarm)
self.countdown = StringVar(self.alarm, "")
self.l2 = Label(self.alarm, textvariable=self.countdown)
self.b0 = Button(self.alarm, text = 'Start countdown', command = lambda : self.timer(reset=True))
self.l0.grid(row = 0, column = 0, columnspan = 2)
self.l1.grid(row = 1, column = 0, padx = 10, pady =5)
self.e0.grid(row = 1, column = 1, padx = 10)
self.l2.grid(row = 2, column = 1, padx = 10)
self.b0.grid(row = 3, column = 0, columnspan = 2, pady = 5)
self.alarm.mainloop()
def timer(self, reset=False):
if reset:
self.b = float(self.e0.get())
self.countdown.set(str(self.b))
self.b-=1
if self.b >= 0:
self.alarm.after(1000, self.timer)
else:
messagebox.showwarning('Alarm Clock', 'Time\'s up!')
if __name__ == '__main__':
my_alarm = alarmclock()
Notice that:
timer
function due to an error in your lambda function definitionself.messagebox.showwarning(_)
throws an error AttributeError: 'alarmclock' object has no attribute 'messagebox'
; messagebox.showwarning(_)
works insteadStringVar
element for convenience (not necessary)By the way, I suggest you to NOT import modules using *
. Try using import tkinter as tk
instead.
Upvotes: 5