Starting and Pausing with a Countdown Timer in Tkinter - python

import tkinter as tk
class Timer:
def __init__(self, master):
self.master = master
master.title("Pomodoro Timer")
self.state = False
self.minutes = 25
self.seconds = 0
self.display = tk.Label(master, height=10, width=10, textvariable="")
self.display.config(text="00:00")
self.display.grid(row=0, column=0, columnspan=2)
self.start_button = tk.Button(master, bg="Green", activebackground="Dark Green", text="Start", width=8, height=4, command=self.start())
self.start_button.grid(row=1, column=0)
self.pause_button = tk.Button(master, bg="Red", activebackground="Dark Red", text="Pause", width=8, height=4, command=self.pause())
self.pause_button.grid(row=1, column=1)
self.countdown()
def countdown(self):
"""Displays a clock starting at min:sec to 00:00, ex: 25:00 -> 00:00"""
mins = self.minutes
secs = self.seconds
if self.state == True:
if secs < 10:
if mins < 10:
self.display.config(text="0%d : 0%d" % (mins, secs))
else:
self.display.config(text="%d : 0%d" % (mins, secs))
else:
if mins < 10:
self.display.config(text="0%d : %d" % (mins, secs))
else:
self.display.config(text="%d : %d" % (mins, secs))
if (mins == 0) and (secs == 0):
self.display.config(text="Done!")
else:
if secs == 0:
mins -= 1
secs = 59
else:
secs -= 1
self.master.after(1000, self.countdown())
elif self.state == False:
self.master.after(100, self.countdown())
def start(self):
if self.state == False:
self.state = True
def pause(self):
if self.state == True:
self.state = False
root = tk.Tk()
my_timer = Timer(root)
root.mainloop()
Pretty new to Python in general, am attempting to make what is essentially a simple countdown timer with start and pause abilities.
What I thought would work would be to call the countdown function right when the window was initiated, having it continually check the "state" of the window through a recursive call. When the "state" is False the countdown function would skip over the "timer" portion of the countdown function and call it again to see if the "state" had changed.
When the user clicks the start button the "state" would change to True and the countdown function would now see the "state" had changed and then would begin actually counting down.
Then when the user clicked the pause button the "state" would change to False again and the countdown function would again skip over the "timer" portion of the function and simply call it again.
Issue I keep running into is something like:
RecursionError: maximum recursion depth exceeded in comparison
Not sure how I can get around this error with the implementation I currently have.
Edit:
So changing self.countdown() to self.countdown in both instances (not under init) does fix the error, but now the function simply is "stuck". The desired window appears, but none of the buttons appear to be working.

command=, after() and bind() needs function name without () (sometimes it is called callback)
countdown() is executed by after() like any other function (but later), and it means:
countdown() recreates all local values in every execution so they don't keep values. You have to use self.mins and self.secs to keep values.
inside countdown() you can't use
mins = self.minutes
secs = self.seconds
because it resets time to 25:00 in every execution. You have to set it in start()
Working code
import tkinter as tk
class Timer:
def __init__(self, master):
self.master = master
master.title("Pomodoro Timer")
self.state = False
self.minutes = 25
self.seconds = 0
self.mins = 25
self.secs = 0
self.display = tk.Label(master, height=10, width=10, textvariable="")
self.display.config(text="00:00")
self.display.grid(row=0, column=0, columnspan=2)
self.start_button = tk.Button(master, bg="Green", activebackground="Dark Green", text="Start", width=8, height=4, command=self.start)
self.start_button.grid(row=1, column=0)
self.pause_button = tk.Button(master, bg="Red", activebackground="Dark Red", text="Pause", width=8, height=4, command=self.pause)
self.pause_button.grid(row=1, column=1)
self.countdown()
def countdown(self):
"""Displays a clock starting at min:sec to 00:00, ex: 25:00 -> 00:00"""
if self.state == True:
if self.secs < 10:
if self.mins < 10:
self.display.config(text="0%d : 0%d" % (self.mins, self.secs))
else:
self.display.config(text="%d : 0%d" % (self.mins, self.secs))
else:
if self.mins < 10:
self.display.config(text="0%d : %d" % (self.mins, self.secs))
else:
self.display.config(text="%d : %d" % (self.mins, self.secs))
if (self.mins == 0) and (self.secs == 0):
self.display.config(text="Done!")
else:
if self.secs == 0:
self.mins -= 1
self.secs = 59
else:
self.secs -= 1
self.master.after(1000, self.countdown)
else:
self.master.after(100, self.countdown)
def start(self):
if self.state == False:
self.state = True
self.mins = self.minutes
self.secs = self.seconds
def pause(self):
if self.state == True:
self.state = False
root = tk.Tk()
my_timer = Timer(root)
root.mainloop()
EDIT: as #EL3PHANTEN pointed out you can use string formatting to make it shorter:
text='{:02} : {:02}'.format(self.mins,self.secs)
or
text="%02d : %02d" % (self.mins,self.secs)
I also moved line self.countdown() from __init__ to start() and now I don't need second after() inside countdown().
I also set self.state = False when it displays Done!
import tkinter as tk
class Timer:
def __init__(self, master):
self.master = master
master.title("Pomodoro Timer")
self.state = False
self.minutes = 25
self.seconds = 0
self.mins = 25
self.secs = 0
self.display = tk.Label(master, height=10, width=10, textvariable="")
self.display.config(text="00:00")
self.display.grid(row=0, column=0, columnspan=2)
self.start_button = tk.Button(master, bg="Green", activebackground="Dark Green", text="Start", width=8, height=4, command=self.start)
self.start_button.grid(row=1, column=0)
self.pause_button = tk.Button(master, bg="Red", activebackground="Dark Red", text="Pause", width=8, height=4, command=self.pause)
self.pause_button.grid(row=1, column=1)
def countdown(self):
"""Displays a clock starting at min:sec to 00:00, ex: 25:00 -> 00:00"""
if self.state == True:
if (self.mins == 0) and (self.secs == 0):
self.display.config(text="Done!")
self.state = False
else:
self.display.config(text="%02d:%02d" % (self.mins, self.secs))
if self.secs == 0:
self.mins -= 1
self.secs = 59
else:
self.secs -= 1
self.master.after(1000, self.countdown)
def start(self):
if self.state == False:
self.state = True
self.mins = self.minutes
self.secs = self.seconds
self.countdown()
def pause(self):
if self.state == True:
self.state = False
root = tk.Tk()
my_timer = Timer(root)
root.mainloop()
"{:02} : {:02}".format(10, 0)

Related

Tkinter GUI Won't Start - Thread - Tkinter object has no attribute 'Label'

I have a Tkinter GUI, which I have copy pasted from one of my other files.
The two GUI's are exact copies, 1:1. The first one works, the second doesn't.
This is the second file, with the TKinter GUI:
import mysql.connector
import threading
import tkinter as tk
import pip
import time
import mysql.connector
from time import sleep
global score
global countdown
en = "1"
score = 0
countdown = 1
tidMål = 0
tidScoreNu = 0
print("Hiya!")
mydb = mysql.connector.connect(
host="",
user="",
password="",
database='',
auth_plugin=''
)
mycursor = mydb.cursor(prepared=True)
#MysQl commands til at interface det hele
class Mysql(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.daemon = True
self.en = 1
self.læsTidScoreNu = "SELECT tidSCoreNu FROM bois WHERE id = 1"
self.læsTidMål = "SELECT tidMål FROM bois WHERE id = 1"
self.opdaterTidMål = "UPDATE bois SET tidMål = %s WHERE id = %s"
self.læsStopKnap = "SELECT stopKnap FROM bois WHERE id = 1"
self.run()
def run(self) -> None:
global mycursor
global mydb
mycursor.execute(self.læsTidScoreNu)
self.råTidScoreNu = mycursor.fetchone()
self.tidScoreNu = float("{}".format('%.2f' % self.råTidScoreNu))
mycursor.execute(self.læsTidMål)
self.råTidMål = mycursor.fetchone()
self.tidMål = float("{}".format('%.2f' % self.råTidMål))
mycursor.execute(self.læsStopKnap)
self.stopKnap = mycursor.fetchone()
mydb.commit()
#Control GUI til admin portalen
class Tkinter(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.daemon = True
self.root = 0
self.entry = 0
self.label = 0
self.button = 0
self.timerValue = 2
self.stopButton = 0
self.start()
self.spilSlut = 0
def run(self) -> 0:
self.root = tk.Tk()
global countdown
#Baggrund
self.root.geometry("+2+0")
self.root.config(background="Grey")
#Timervalue selectors
self.label = tk.Label(self.root, bg="white", fg="black", font=("Fixedsys", 28))
self.entry = tk.Entry(self.root, bg="white", fg="black", font=("Fixedsys", 28))
#Start/Stop Knapper
self.stopTiden = tk.Button(self.root, bg="red", fg="white", text="Stop Spillet", command=self.stopTid)
self.startTiden = tk.Button(self.root, bg="green", fg="white", text="Start Spillet", command=self.startTid)
#Timeren
self.timerDisplay = tk.Label(self.root, bg="black", fg="red", text="Spillet er ikke startet")
self.timerDisplay.grid(row=2, column=50)
self.startTiden.grid(row=0, column=1)
self.stopTiden.grid(row=0, column=10)
self.entry.grid(row=1, column=1)
self.label.grid(row=1, column=10)
self.root.bind("<KeyPress>", self.read)
self.Update(self)
self.root.mainloop()
def read(self, event):
key = event.keysym
try:
if key == "Return":
self.getA()
self.visTid()
except:
self.fejlTidvalg()
def startTid(self):
self.stopButton = 0
def getA(self):
try:
self.timerValue = float(self.entry.get().format("%.2f", 1.23456))
print(self.timerValue)
return self.timerValue
except:
print(fejl)
def stopTid(self):
self.stopButton = 1
print("Spillet er stoppet nu")
def visTid(self):
self.label.config(text="Det her er timerens slutværdi: {}".format(self.timerValue))
def fejlTidvalg(self):
self.label.config(text="FEJL -Vælg Venligst Et Tal")
def opdaterCountdown(self):
if self.stopButton != 1:
self.spilSlut = 0
self.tidTilbage = self.timerValue - countdown
self.tidTilbage_minutter = int(self.tidTilbage/60)
self.tidTilbage_sekunder = (self.tidTilbage) - (self.tidTilbage_minutter * 60)
self.timerDisplay.config(text="{} minutter, {:.2f} sekunder tilbage".format(self.tidTilbage_minutter, self.tidTilbage_sekunder))
if self.tidTilbage < 0 or self.tidTilbage == 0 and self.timerValue > 0:
self.spilSlut = 1
elif self.stopButton == 1:
self.timerDisplay.config(text="Spillet er sat på pause")
def opdaterCountdownSpilSlut(self):
self.timerDisplay.config(text="Spillet er slut")
class Update(threading.Thread):
def __init__(self, tkinter):
threading.Thread.__init__(self)
self.daemon = True
self.tkinter = tkinter
self.start()
def run(self) -> None:
while True:
time.sleep(0.1)
self.tkinter.opdaterCountdown()
if self.tkinter.spilSlut == 1:
self.tkinter.opdaterCountdownSpilSlut()
time.sleep(1)
tk = Tkinter()
data = Mysql()
while True:
print()
The error I get is this:
Exception in thread Thread-1:
Traceback (most recent call last):
File "C:\Users\Mandem\AppData\Local\Programs\Python\Python38-32\lib\threading.py", line 932, in _bootstrap_inner
self.run()
File "C:/Users/Mandem/AppData/Local/Programs/Python/Python38-32/Lib/site-packages/mysql/connector/PC-ADMIN-Camper.py", line 81, in run
self.label = tk.Label(self.root, bg="white", fg="black", font=("Fixedsys", 28))
AttributeError: 'Tkinter' object has no attribute 'Label'
I have been looking around the forum for solutions, and it usually turns out to be something about running the function/variable before defining it. Thing is, I HAVE defined it before running it, and, the exact same code runs perfectly well in my first program.
GUI from my first program:
import threading
import tkinter as tk
import pip
import time
import mysql.connector
from time import sleep
global score
global countdown
en = "1"
score = 0
countdown = 1
print("Hiya!")
class Tkinter(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.daemon = True
self.root = 0
self.entry = 0
self.label = 0
self.button = 0
self.timerValue = 2
self.stopButton = 0
self.start()
self.spilSlut = 0
def run(self) -> 0:
self.root = tk.Tk()
global countdown
#Baggrund
self.root.geometry("+2+0")
self.root.config(background="Grey")
#Timervalue selectors
self.label = tk.Label(self.root, bg="white", fg="black", font=("Fixedsys", 28))
self.entry = tk.Entry(self.root, bg="white", fg="black", font=("Fixedsys", 28))
#Start/Stop Knapper
self.stopTiden = tk.Button(self.root, bg="red", fg="white", text="Stop Spillet", command=self.stopTid)
self.startTiden = tk.Button(self.root, bg="green", fg="white", text="Start Spillet", command=self.startTid)
#Timeren
self.timerDisplay = tk.Label(self.root, bg="black", fg="red", text="Spillet er ikke startet")
self.timerDisplay.grid(row=2, column=50)
self.startTiden.grid(row=0, column=1)
self.stopTiden.grid(row=0, column=10)
self.entry.grid(row=1, column=1)
self.label.grid(row=1, column=10)
self.root.bind("<KeyPress>", self.read)
self.Update(self)
self.root.mainloop()
def read(self, event):
key = event.keysym
try:
if key == "Return":
self.getA()
self.visTid()
except:
self.fejlTidvalg()
def startTid(self):
self.stopButton = 0
def getA(self):
try:
self.timerValue = float(self.entry.get().format("%.2f", 1.23456))
print(self.timerValue)
return self.timerValue
except:
print(fejl)
def stopTid(self):
self.stopButton = 1
print("Spillet er stoppet nu")
def visTid(self):
self.label.config(text="Det her er timerens slutværdi: {}".format(self.timerValue))
def fejlTidvalg(self):
self.label.config(text="FEJL -Vælg Venligst Et Tal")
def opdaterCountdown(self):
if self.stopButton != 1:
self.spilSlut = 0
self.tidTilbage = self.timerValue - countdown
self.tidTilbage_minutter = int(self.tidTilbage/60)
self.tidTilbage_sekunder = (self.tidTilbage) - (self.tidTilbage_minutter * 60)
self.timerDisplay.config(text="{} minutter, {:.2f} sekunder tilbage".format(self.tidTilbage_minutter, self.tidTilbage_sekunder))
if self.tidTilbage < 0 or self.tidTilbage == 0 and self.timerValue > 0:
self.spilSlut = 1
elif self.stopButton == 1:
self.timerDisplay.config(text="Spillet er sat på pause")
def opdaterCountdownSpilSlut(self):
self.timerDisplay.config(text="Spillet er slut")
class Update(threading.Thread):
def __init__(self, tkinter):
threading.Thread.__init__(self)
self.daemon = True
self.tkinter = tkinter
self.start()
def run(self) -> None:
while True:
time.sleep(0.1)
self.tkinter.opdaterCountdown()
if self.tkinter.spilSlut == 1:
self.tkinter.opdaterCountdownSpilSlut()
time.sleep(1)
app = Tkinter()
How come the same (exact same) GUI works in the first, but not in the second?
Have I made a typo, that I for some reason cannot find? Or is there something else I have missed?
The two GUI's are exact copies, 1:1.
That is a false statement. One does app = Tkinter() and the other does tk = Tkinter().
You are using tk for two different things:
import tkinter as tk
...
tk = Tkinter()
You need to change that last line to use a different variable name.

Tkinter Label text doesn't change every time

Python 3.6.
This is a class i made for tkinter, where the text of self.compteur changes every second once i press start :
motsCount = 0
temps_total = 3600
class ChronoAspi:
def __init__(self, master):
self.master = master
self.mainframe = tkinter.Frame(self.master, background ='#28aae1')
self.mainframe.pack(fill = tkinter.BOTH, expand= True)
self.timer_text = tkinter.StringVar()
self.timer_text.trace('w', self.build_timer)
self.time_left = tkinter.IntVar()
self.time_left.set(temps_total)
self.running = True
self.buildGrid()
self.build_buttons()
self.build_timer()
self.build_compteur()
self.update()
def buildGrid(self):
self.mainframe.columnconfigure(0, weight=1)
self.mainframe.rowconfigure(0, weight=1)
self.mainframe.rowconfigure(1, weight=1)
self.mainframe.rowconfigure(2, weight=0)
def build_buttons(self):
buttons_frame = tkinter.Frame(self.mainframe)
buttons_frame.grid(row=2, column=0, sticky='nsew', padx=10, pady=10)
buttons_frame.columnconfigure(0, weight=1)
buttons_frame.columnconfigure(1, weight=1)
self.start_button = tkinter.Button(buttons_frame, text='Start', command=self.start_timer )
self.stop_button = tkinter.Button(buttons_frame, text='Stop', command=self.stop_timer)
self.start_button.grid(row=0, column=0, sticky = 'ew')
self.stop_button.grid(row=0, column=1, sticky = 'ew')
self.stop_button.config(state=tkinter.DISABLED)
def build_timer(self, *args):
timer = tkinter.Label(self.mainframe, text=self.timer_text.get(), background = '#28aae1', fg='white', font=("Helvetica", 30))
timer.grid(row=1, column=0)
def build_compteur(self, *args):
self.compteur = tkinter.Label(self.mainframe, text='Aucun mot compté.', background = '#28aae1', fg='white', font=("Helvetica", 20))
self.compteur.grid(row=0, column=0)
def start_timer(self):
self.time_left.set(temps_total)
self.running = True
self.stop_button.config(state=tkinter.NORMAL)
self.start_button.config(state=tkinter.DISABLED)
def stop_timer(self):
self.running = False
self.stop_button.config(state=tkinter.DISABLED)
self.start_button.config(state=tkinter.NORMAL)
def heures_minutes_secondes(self, seconds):
return int(seconds/3600), int(seconds%3600/60), int(seconds%60)
def update(self):
global motsCount
time_left = self.time_left.get()
if self.running and time_left:
heure, minutes, seconds = self.heures_minutes_secondes(time_left)
self.timer_text.set('{:0>2}:{:0>2}:{:0>2}'.format(heure ,minutes, seconds) )
self.time_left.set(time_left-1)
motsCount += 1
else:
heure, minutes, seconds = self.heures_minutes_secondes(time_left)
self.timer_text.set( '{:0>2}:{:0>2}:{:0>2}'.format(heure ,minutes, seconds))
self.compteur['text'] = 'Compteur stoppé.'
self.stop_timer()
if motsCount > 0:
self.compteur['text'] = str(motsCount) + ' mots comptés.'
self.master.after(1000, self.update)
if __name__ == '__main__':
root = tkinter.Tk()
ChronoAspi(root)
root.mainloop()
As long as the chronometer is running, the text of self.compteurchanges every second. But when i hit the self.stop_button, self.running becomes False and the else part in the update() function is executed. So the chronometer stops but the self.compteur text doesn't change and I don't know why!
Sorry I can't comment but I think your if statement is gonna run after self.stopTimer returns and gonna change the text back

Python Tkinter Stopwatch Error

i have made a double countdown timer with python and tkinter but it seemed that it cannot be run if the tkinter window is not on the foreground and it cannot simultaneously run. This is my code:
import tkinter as tk
import tkinter.ttk as ttk
import time
class app:
def __init__(self):
self = 0
def mainGUIArea():
def count_down_1():
for i in range(79, -1, -1):
timeCount = "{:02d}:{:02d}".format(*divmod(i, 60))
time_str.set(timeCount)
root.update()
time.sleep(1)
def count_down_2():
for j in range(10, -1, -1):
timeCount = "{:02d}:{:02d}".format(*divmod(j, 60))
time_str1.set(timeCount)
root.update()
time.sleep(1)
#Main Window
root = tk.Tk()
root.title("Super Timer V1.0")
root.minsize(300,300)
root.geometry("500x300")
#Timer1
time_str = tk.StringVar()
label_font = ('Courier New', 40)
tk.Label(root, textvariable = time_str, font = label_font, bg = 'white', fg = 'blue', relief = 'raised', bd=3).pack(fill='x', padx=5, pady=5)
tk.Button(root, text=' Start Timer! ',bg='lightgreen',fg='black', command=count_down_1).pack()
tk.Button(root, text='Stop and Exit',bg='red',fg='white', command=root.destroy).pack()
#Timer2
time_str1 = tk.StringVar()
label_font = ('Courier New', 40)
tk.Label(root, textvariable = time_str1, font = label_font, bg = 'white', fg='blue', relief='raised', bd=3).pack(fill='x', padx=5, pady=5)
tk.Button(root, text=' Start Timer! ',bg='lightblue',fg='black', command=count_down_2).pack()
tk.Button(root, text='Stop and Exit',bg='red',fg='white', command=root.destroy).pack()
def main():
app.mainGUIArea()
main()
Do you have any suggestion? Thank You :)
The calls to time.sleep are at least part of the problem. When you call sleep it does literally that -- it puts the application to sleep. No events can be processed and the GUI freezes. This is the wrong way to do a countdown timer.
The other problem is the calls to update inside the loops alongside the calls to time.sleep. This call will process events, which means that when one of the loops is running and you click a button, you may end up calling the other function, interleaving your two loops.
The proper way to do something periodically is to use after to repeatedly call a function. The general pattern is this:
def update_display(self):
<do whatever code you want to update the display>
root.after(1000, self.update_display)
You can have as many of these running in parallel that you want (up to practical limits, obviously), and your GUI will be completely responsive between updates.
Here's a quick example:
class Countdown(tk.Label):
def __init__(self, parent):
tk.Label.__init__(self, parent, width=5, text="00:00")
self.value = 0
self._job_id = None
def tick(self):
self.value -= 1
text = "{:02d}:{:02d}".format(*divmod(self.value, 60))
self.configure(text=text)
if self.value > 0:
self._job_id = self.after(1000, self.tick)
def start(self, starting_value=60):
if self._job_id is not None: return
self.value = starting_value
self.stop_requested = False
self.after(1000, self.tick)
def stop(self):
self.after_cancel(self._job_id)
self._job_id = None
This is a simple tkinter(gui) stopwatch I made which works perfectly. Check it out
__author__ = 'Surya'
from tkinter import *
import time
class StopWatch(Frame):
def __init__(self, parent = None, ** kw):
Frame.__init__(self, parent, kw)
self._timeelapsed = 0.0
self._start = 0.0
self._run = 0
self.timestr = StringVar()
self.makeWidgets()
def makeWidgets(self):
l = Label(self, textvariable=self.timestr)
self._setTime(self._timeelapsed)
l.pack(fill=X, expand=NO, pady=2, padx=2)
def _update(self):
self._timeelapsed = time.time() - self._start
self._setTime(self._timeelapsed)
self._timer = self.after(50, self._update)
def _setTime(self, elap):
minutes = int(elap/60)
seconds = int(elap - minutes*60.0)
hseconds = int((elap - minutes*60.0 - seconds)*100)
self.timestr.set('%02d:%02d:%02d' % (minutes, seconds, hseconds))
def Start(self):
if not self._run:
self._start = time.time() - self._timeelapsed
self._update()
self._run = 1
def Stop(self):
if self._run:
self.after_cancel(self._timer)
self._timeelapsed = time.time() - self._start
self._setTime(self._timeelapsed)
self._run = 0
def Reset(self):
self._start = time.time()
self._timeelapsed = 0.0
self._setTime(self._timeelapsed)
def main():
root = Tk()
sw = StopWatch(root)
sw.pack(side=TOP)
Button(root, text='Start!', command=sw.Start).pack(side=LEFT)
Button(root, text='Stop!', command=sw.Stop).pack(side=LEFT)
Button(root, text='Reset!!!', command=sw.Reset).pack(side=LEFT)
Button(root, text='Quit!!!', command=root.quit).pack(side=LEFT)
root.mainloop()
if __name__ == '__main__':
main()

python: Converting code to a class

I am just learning python and jumping into classes. I have been using the following code for a simple stopwatch that I found. I now want to create a class with this code. I will have 1-4 timers on the screen at any one time. I need to start them all at the same time but end each timer independently. I am still plugging away at this but any help would be much appreciated.
import Tkinter as tk
def update_timeText():
if (state):
global timer
timer[2] += 1
if (timer[2] >= 100):
timer[2] = 0
timer[1] += 1
if (timer[1] >= 60):
timer[0] += 1
timer[1] = 0
timeString = pattern.format(timer[0], timer[1], timer[2])
timeText.configure(text=timeString)
root.after(10, update_timeText)
def start():
global state
state = True
def pause():
global state
state = False
def reset():
global timer
timer = [0, 0, 0]
timeText.configure(text='00:00:00')
def exist():
root.destroy()
state = False
root = tk.Tk()
root.wm_title('Simple Kitchen Timer Example')
timer = [0, 0, 0]
pattern = '{0:02d}:{1:02d}:{2:02d}'
timeText = tk.Label(root, text="00:00:00", font=("Helvetica", 150))
timeText.pack()
startButton = tk.Button(root, text='Start', command=start)
startButton.pack()
pauseButton = tk.Button(root, text='Pause', command=pause)
pauseButton.pack()
resetButton = tk.Button(root, text='Reset', command=reset)
resetButton.pack()
quitButton = tk.Button(root, text='Quit', command=exist)
quitButton.pack()
To create a class simply try this:
import Tkinter as tk
class StopWatch(object): # sub-class the object class maybe
def update_timeText(self):
#your code logic...
def start(self):
#your code logic...
#etc...
#the rest of your functions are the same
#just specify the 'self' Python keyword before any other arguments in the function. :D
Let me know if this works. :D
Here is my solution. It took me so long to get my head around the class creation of this. Any ideas for improving this?
import Tkinter as tk
root = tk.Tk()
root.wm_title('Stopwatch Class')
root.geometry("300x350")
class StopWatch(object):
def __init__(self):
self.pattern = '{0:02d}:{1:02d}:{2:02d}'
self.timer = [0, 0, 0]
self.state = False
self.timeText = tk.Label(root, text='00:00:01', font=("Helvetica", 15))
self.timeText.pack()
self.startButton = tk.Button(root, text='Start', command=self.start)
self.startButton.pack()
self.resetButton = tk.Button(root, text='Reset', command=self.reset)
self.resetButton.pack()
self.pauseButton = tk.Button(root, text='Pause', command=self.pause)
self.pauseButton.pack()
def update_timeText(self):
if (self.state):
self.timer[2] += 1
if (self.timer[2] >= 100):
self.timer[2] = 0
self.timer[1] += 1
if (self.timer[1] >= 60):
self.timer[0] += 1
self.timer[1] = 0
self.timeString = self.pattern.format(self.timer[0], self.timer[1], self.timer[2])
self.timeText.configure(text=self.timeString)
root.after(10, self.update_timeText)
def start(self):
self.state = True
def pause(self):
self.state = False
def reset(self):
self.timer = [0, 0, 0]
self.timeText.configure(text='00:00:00')
# create a new stopwatch
swatch1 = StopWatch()
swatch1.update_timeText()
# create a new stopwatch
swatch2 = StopWatch()
swatch2.update_timeText()
# create a new stopwatch
swatch3 = StopWatch()
swatch3.update_timeText()
root.mainloop()

Python timer in math game Tkinter

I'm looking to add a timer for my simple math game. So far everything works just fine, the user gets questions when pressing the button and is given feedback on the answer. I want to add a timer for the user to see how much time it takes to answer the multiplication. This is the final part of my prototype to this mathgame. I want the timer to start when the user clicks "nytt tal" which means new number in swedish, and to stopp when the user clicks "svar" which means answer in swedish. Here is my code.
from Tkinter import *
import tkMessageBox
import random
import time
import sys
# Definition for the question asked to user
def fraga1():
global num3
num3 = random.randint(1, 10)
global num4
num4 = random.randint(1, 10)
global svar1
svar1 = num3 * num4
label1.config(text='Vad blir ' + str(num3) + '*' + str(num4) + '?')
entry1.focus_set()
#The answer giving feedback based on answer
def svar1():
mainAnswer = entry1.get()
if len(mainAnswer) == 0:
tkMessageBox.showwarning(message='Skriv in några nummer!')
return
if int(mainAnswer) != svar1:
tkMessageBox.showwarning(message='Tyvärr det rätta svaret: ' + str(svar1))
else:
tkMessageBox.showinfo(message='RÄTT!! :)')
#The quit button definition
def quit():
global root
root.destroy()
#Definition for the timer this part doesnt work
def start():
global count_flag
fraga1()
count_flag = True
count = 0.0
while True:
if count_flag == False:
break
label['text'] = str(count)
time.sleep(0.1)
root.update()
count += 0.1
#Window code
root = Tk()
root.title("multiplikations tidtagning")
root.geometry('800x500')
count_flag = True
# Welcome message in labels
label2 = Label(root, text="Hej!\n Nu ska vi lösa lite matteproblem!")
label2.config(font=('times', 18, 'bold'), fg='black', bg='white')
label2.grid(row=0, column=0)
#Instructions how to play in labels
label3 = Label(root, text="Instruktioner!\n För att starta ett spel tryck på nyttspel")
label3.config(font=('times', 12, 'bold'), fg='black', bg='white')
label3.grid(row=2, column=2)
#other label
label1 = Label(root)
label1.grid(row=2, column=0)
# entry widget for the start button
entry1 = Entry(root)
entry1.grid(row=3, column=0)
# restart gives a new question
entry1.bind('', func=lambda e:checkAnswer())
#Buttons
fragaBtn = Button(root, text='Nytt tal', command=fraga1)
fragaBtn.grid(row=4, column=0)
svarButton = Button(root, text='Svar', command=svar1)
svarButton.grid(row=4, column=1)
quit_bttn = Button(root, text = "Avsluta", command=quit)
quit_bttn.grid(row=5, column=0)
root.mainloop()
I think what you need is this .
from Tkinter import *
import time
class StopWatch(Frame):
""" Implements a stop watch frame widget. """
def __init__(self, parent=None, **kw):
Frame.__init__(self, parent, kw)
self._start = 0.0
self._elapsedtime = 0.0
self._running = 0
self.timestr = StringVar()
self.makeWidgets()
def makeWidgets(self):
""" Make the time label. """
l = Label(self, textvariable=self.timestr)
self._setTime(self._elapsedtime)
l.pack(fill=X, expand=NO, pady=2, padx=2)
def _update(self):
""" Update the label with elapsed time. """
self._elapsedtime = time.time() - self._start
self._setTime(self._elapsedtime)
self._timer = self.after(50, self._update)
def _setTime(self, elap):
""" Set the time string to Minutes:Seconds:Hundreths """
minutes = int(elap/60)
seconds = int(elap - minutes*60.0)
hseconds = int((elap - minutes*60.0 - seconds)*100)
self.timestr.set('%02d:%02d:%02d' % (minutes, seconds, hseconds))
def Start(self):
""" Start the stopwatch, ignore if running. """
if not self._running:
self._start = time.time() - self._elapsedtime
self._update()
self._running = 1
def Stop(self):
""" Stop the stopwatch, ignore if stopped. """
if self._running:
self.after_cancel(self._timer)
self._elapsedtime = time.time() - self._start
self._setTime(self._elapsedtime)
self._running = 0
def Reset(self):
""" Reset the stopwatch. """
self._start = time.time()
self._elapsedtime = 0.0
self._setTime(self._elapsedtime)
def main():
root = Tk()
sw = StopWatch(root)
sw.pack(side=TOP)
Button(root, text='Start', command=sw.Start).pack(side=LEFT)
Button(root, text='Stop', command=sw.Stop).pack(side=LEFT)
Button(root, text='Reset', command=sw.Reset).pack(side=LEFT)
Button(root, text='Quit', command=root.quit).pack(side=LEFT)
root.mainloop()
if __name__ == '__main__':
main()
P.S: Fit this in your code I just implemented the basic timer in tkinter.
well if you're using a tkinter you're use the function
object.after(100, defineFunction)
the first parent is the milisecond
this'll apply to python3.x but 2.7 i cant be sure since i dont pratice that format
Use a global variable storing current time when person presses start. Then when the user presses svar in your function svar, just fetch current time, substract them from one another and you get time taken, then reset the global var to 0 also and voila, you have the time taken
I can suggest additional solution with threading.
I hold a small timer in one of my projects and it run as a different thread and gets updated each second:
import threading
import tkinter as tk
import time
root = tk.Tk()
timer = tk.Text(root, width=5, height=1)
timer.insert(tk.INSERT, "00:00")
timer.pack()
def show_time():
start = time.time()
seconds = 0
while True:
if time.time() - start > 1:
seconds += int(time.time() - start)
start = time.time()
cur_index = timer.index(tk.INSERT)
cur_index = str(int(cur_index[0]) - 1) + cur_index[1:]
timer.delete(cur_index, tk.INSERT)
timer.insert(tk.INSERT, str(int(seconds / 60)) + ":" + str(seconds % 60))
root.update()
thread = threading.Thread(target=show_time)
thread.start()
I think you can use "after".
You create a widget...
time = 60 #60 seconds for example
widget = Tkinter.Label().pack()
def count():
global time
if time > 0:
time -= 1
widget.config(text="Time left: " + str(time))
widget.after(1000, count)
I use python 3x
Sorry

Categories

Resources