Python Tkinter Stopwatch Error - python

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()

Related

I can not figure out why my app menu is still freezing after I have used threading on tkinter

When I run the app, the run button is still responsive for a few seconds before the entire app freezes but the thread continues running. Where is the problem in my code and how do fix it?
import threading
from tkinter import *
from tkinter import ttk
class SubExtractor:
def __init__(self, root):
self.root = root
self._create_layout()
def _create_layout(self):
self.root.title("Sub Extractor")
self._menu_bar()
self.main_frame = ttk.Frame(self.root, padding=(5, 5, 5, 15))
self._video_frame()
self._progress_frame()
self._output_frame()
self.main_frame.grid()
def _menu_bar(self):
self.root.option_add('*tearOff', FALSE)
menubar = Menu(self.root)
self.root.config(menu=menubar)
menu_file = Menu(menubar)
menu_settings = Menu(menubar)
menubar.add_cascade(menu=menu_file, label="File")
menubar.add_cascade(menu=menu_settings, label="Settings")
menu_file.add_command(label="Open", command=self._open_file)
menu_file.add_command(label="Close", command=self._close_window)
menu_settings.add_command(label="Language", command=self._language_settings)
menu_settings.add_command(label="Extraction", command=self._extraction_settings)
def _video_frame(self):
video_frame = ttk.Frame(self.main_frame, borderwidth=2, relief="ridge", width=1000, height=600)
video_frame.grid()
def _progress_frame(self):
progress_frame = ttk.Frame(self.main_frame)
progress_frame.grid(row=1, sticky="W")
self.run_button = ttk.Button(progress_frame, text="Run", command=self._run)
self.run_button.grid(pady=10, padx=30)
self.progress_bar = ttk.Progressbar(progress_frame, orient=HORIZONTAL, length=800, mode='determinate')
self.progress_bar.grid(column=2, row=0)
def _output_frame(self):
output_frame = ttk.Frame(self.main_frame)
output_frame.grid(row=2)
self.text_output_widget = Text(output_frame, width=97, height=12, state="disabled")
self.text_output_widget.grid()
output_scroll = ttk.Scrollbar(output_frame, orient=VERTICAL, command=self.text_output_widget.yview)
output_scroll.grid(column=1, row=0, sticky="N,S")
self.text_output_widget.configure(yscrollcommand=output_scroll.set)
def _close_window(self):
self._stop_run()
self.root.quit()
def _stop_run(self):
self.interrupt = True
self.run_button.configure(text="Run", command=self._run)
def _text_to_output(self, text):
self.text_output_widget.configure(state="normal")
self.text_output_widget.insert("end", f"{text}\n")
self.text_output_widget.see("end")
self.text_output_widget.configure(state="disabled")
def long_running_method(self):
num = 100000
self.progress_bar.configure(maximum=num)
for i in range(0, num):
if self.interrupt:
break
self._text_to_output(f"Line {i} of {num}")
self.progress_bar['value'] += 1
self._stop_run()
def _run(self):
self.interrupt = False
self.run_button.configure(text='Stop', command=self._stop_run)
threading.Thread(target=self.long_running_method).start()
rt = Tk()
SubtitleExtractorGUI(rt)
rt.mainloop()
What I expect to accomplish is for the loop to insert texts in the text widget while I can still freely move and use other buttons on the app.

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

Attributeerror: 'int' object has no attribute 'insert'

Basically when i run this on windows it has no error however i run it in linux, i shows Attributeerror: 'int' object has no attribute 'insert'. What is the problem anyone?
The insert can be found in the Lap method , self.m.insert(END, self.laps[-1]).
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.e = 0
self.m = 0
self.makeWidgets()
self.laps = []
self.lapmod2 = 0
self.today = time.strftime("%d %b %Y %H-%M-%S", time.localtime())
def makeWidgets(self):
""" Make the time label. """
l1 = Label(self, text='----File Name----')
l1.pack(fill=X, expand=NO, pady=1, padx=2)
self.e = Entry(self)
self.e.pack(pady=2, padx=2)
l = Label(self, textvariable=self.timestr)
self._setTime(self._elapsedtime)
l.pack(fill=X, expand=NO, pady=3, padx=2)
l2 = Label(self, text='----Laps----')
l2.pack(fill=X, expand=NO, pady=4, padx=2)
scrollbar = Scrollbar(self, orient=VERTICAL)
self.m = Listbox(self,selectmode=EXTENDED, height = 10,font=("Helvetica", 12),yscrollcommand=scrollbar.set)
self.m.pack(side=LEFT, fill=BOTH, expand=1, pady=5, padx=2)
scrollbar.config(command=self.m.yview)
scrollbar.pack(side=RIGHT, fill=Y)
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 _setLapTime(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)
return '%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.laps = []
self._setTime(self._elapsedtime)
def Lap(self):
'''Makes a lap, only if started'''
tempo = self._elapsedtime - self.lapmod2
if self._running:
self.laps.append(self._setLapTime(tempo))
self.m.insert(END, self.laps[-1])
self.m.yview_moveto(1)
self.lapmod2 = self._elapsedtime
def GravaCSV(self):
'''Pega nome do cronometro e cria arquivo para guardar as laps'''
arquivo = str(self.e.get()) + ' - '
with open(arquivo + self.today + '.txt', 'wb') as lapfile:
for Lap in self.laps:
lapfile.write((bytes(str(Lap) + '\n', 'utf-8')))
def main():
root = Tk()
root.wm_attributes("-topmost", 1)
sw = StopWatch(root)
sw.pack(side=TOP)
Button(root, text='Lap', command=sw.Lap).pack(side=LEFT)
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='Save', command=sw.GravaCSV).pack(side=LEFT)
Button(root, text='Quit', command=root.quit).pack(side=LEFT)
root.mainloop()
if __name__ == '__main__':
main()
It looks like the interpreter is somehow calling the Lap() method before it calls makeWidgets(), which is weird because I don't see Lap() being called anywhere in the provided code. Is this an MCVE?
Instead of initializing self.m as 0 in your __init__(), initialize it with the value it's supposed to have: a Listbox widget.
Remove self.m = 0 from __init__()
Move self.m = Listbox(self,selectmode=EXTENDED, height = 10,font=("Helvetica", 12),yscrollcommand=scrollbar.set) from makeWidgets() to __init__()
makeWidgets() is only ever called once anyway, so maybe you could just put all that into the __init__() unless you're planning on expanding the program to call makeWidgets() more than once.
In your StopWatch constructor you declare and set self.m = 0 which is an int. I don't see anywhere in your code that you change self.m to any object that would have an insert method and the int type doesn't have an insert method to be called. When you try to use the method you get the AttributeError.

Python stopwatch example - starting all class instances at the same time?

In this example how can I start all 4 stop watches at the same time?
This example code is over 12 years old but it is the best stopwatch example I have been able to find via Google. You can see that I have 4 instances of the class in use. I need to be able to start all the instances at the exact same time. Tinker button doesn't allow for calling multiple functions. Even if it did it would be one function before the next so technically they wouldn't all start at the exact same time.
I will need to stop each stopwatch at different times but that is easy by just calling each Stop function in the class. But I can't figure out how to start them all at the same time.
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 labels. """
l = Label(self, textvariable=self.timestr)
l.pack(fill=X, expand=NO, pady=2, padx=2)
self._setTime(self._elapsedtime)
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):
global sw2
""" 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()
sw1 = StopWatch(root)
sw1.pack(side=TOP)
sw2 = StopWatch(root)
sw2.pack(side=TOP)
sw3 = StopWatch(root)
sw3.pack(side=TOP)
sw4 = StopWatch(root)
sw4.pack(side=TOP)
Button(root, text='Start', command=sw1.Start).pack(side=LEFT)
Button(root, text='Stop', command=sw1.Stop).pack(side=LEFT)
Button(root, text='Reset', command=sw1.Reset).pack(side=LEFT)
Button(root, text='Quit', command=root.quit).pack(side=LEFT)
root.mainloop()
if __name__ == '__main__':
main()
The following program may be close to want you want. Please note that since it takes time to start and stop the stopwatches, you may find small discrepancies among the times they are showing.
#! /usr/bin/env python3
import tkinter
import time
class StopWatch(tkinter.Frame):
#classmethod
def main(cls):
tkinter.NoDefaultRoot()
root = tkinter.Tk()
root.title('Stop Watch')
root.resizable(True, False)
root.grid_columnconfigure(0, weight=1)
padding = dict(padx=5, pady=5)
widget = StopWatch(root, **padding)
widget.grid(sticky=tkinter.NSEW, **padding)
root.mainloop()
def __init__(self, master=None, cnf={}, **kw):
padding = dict(padx=kw.pop('padx', 5), pady=kw.pop('pady', 5))
super().__init__(master, cnf, **kw)
self.grid_columnconfigure(1, weight=1)
self.grid_rowconfigure(1, weight=1)
self.__total = 0
self.__label = tkinter.Label(self, text='Total Time:')
self.__time = tkinter.StringVar(self, '0.000000')
self.__display = tkinter.Label(self, textvariable=self.__time)
self.__button = tkinter.Button(self, text='Start', command=self.click)
self.__label.grid(row=0, column=0, sticky=tkinter.E, **padding)
self.__display.grid(row=0, column=1, sticky=tkinter.EW, **padding)
self.__button.grid(row=1, column=0, columnspan=2,
sticky=tkinter.NSEW, **padding)
def click(self):
if self.__button['text'] == 'Start':
self.__button['text'] = 'Stop'
self.__start = time.clock()
self.__counter = self.after_idle(self.__update)
else:
self.__button['text'] = 'Start'
self.after_cancel(self.__counter)
def __update(self):
now = time.clock()
diff = now - self.__start
self.__start = now
self.__total += diff
self.__time.set('{:.6f}'.format(self.__total))
self.__counter = self.after_idle(self.__update)
class ManyStopWatch(tkinter.Tk):
def __init__(self, count):
super().__init__()
self.title('Stopwatches')
padding = dict(padx=5, pady=5)
tkinter.Button(self, text='Toggle All', command=self.click).grid(
sticky=tkinter.NSEW, **padding)
for _ in range(count):
StopWatch(self, **padding).grid(sticky=tkinter.NSEW, **padding)
def click(self):
for child in self.children.values():
if isinstance(child, StopWatch):
child.click()
if __name__ == '__main__':
ManyStopWatch(4).mainloop()
"Tinker [sic] button doesn't allow for calling multiple functions."
No, but it can call a single function which can call multiple functions.
def start():
for sw in (sw1, sw2, sw3, sw4):
sw.Start()
...
Button(root, text='Start', command=start).pack(side=LEFT)
You are correct that it is impossible to start them at precisely the same time. Though, they will all be within a millisecond or two of each other so for most situations it's quite good enough. Since you're only displaying the time to the granularity of a whole second, the timers should always show the same time.
If you really need them to be synchronized, you need them to share the same exact start time. You can do that by allowing the stopwatch to be given a start time. Then, you can compute the start time once and pass the same value to all four watches:
class Stopwatch(Frame):
...
def Start(self, starttime=None):
...
if not self._running:
if starttime is None:
self._start = time.time() - self._elapsedtime
else:
self._start = starttime - self.elapsedtime
...
...
t = time.time()
sw1.Start(t)
sw2.Start(t)
sw3.Start(t)
sw4.Start(t)
You could also have a single timer object that all of the stopwatches share. They then aren't so much stopwatches as they are "split timers" -- they can't control the starting of the watch, they can only record the interval that they were stopped at.
Here is what I ended up doing based on Bryan's idea of having one instance of the counter and then taking splits of the time. This works but I have not figured out a way to just use on Getspit function to grab each time. Maybe passing in the a,b,c,d and then an if to get the time? Right now I am doing this with buttons but once implemented it will be grabbing them via events that happen in the main program I am writing. If anyone has any improvements on this please let me know. Thanks to everyone for the help.
from Tkinter import *
import time
import tkMessageBox
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.lapastr = StringVar()
self.lapbstr = StringVar()
self.lapcstr = StringVar()
self.lapdstr = StringVar()
self.makeWidgets()
def makeWidgets(self):
""" Make the time labels. """
la = Label(self, textvariable=self.timestr)
la.pack(fill=X, expand=NO, pady=2, padx=2)
#self._setTime(self._elapsedtime)
lb = Label(self, textvariable=self.timestr)
lb.pack(fill=X, expand=NO, pady=2, padx=2)
#self._setTime(self._elapsedtime)
lc = Label(self, textvariable=self.timestr)
lc.pack(fill=X, expand=NO, pady=2, padx=2)
#self._setTime(self._elapsedtime)
ld = Label(self, textvariable=self.timestr)
ld.pack(fill=X, expand=NO, pady=2, padx=2)
lsplita = Label(self, textvariable=self.lapastr)
lsplita.pack(fill=X, expand=NO, pady=2, padx=2)
lsplitb =Label(self, textvariable=self.lapbstr)
lsplitb.pack(fill=X, expand=NO, pady=2, padx=2)
lsplitc = Label(self, textvariable=self.lapcstr)
lsplitc.pack(fill=X, expand=NO, pady=2, padx=2)
lsplitd = Label(self, textvariable=self.lapdstr)
lsplitd.pack(fill=X, expand=NO, pady=2, padx=2)
self._setTime(self._elapsedtime)
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 Getsplita(self):
""" Stop the stopwatch, ignore if stopped. """
if self._running:
self._lapstr = time.time() - self._start
self._setTime(self._elapsedtime)
self.lapastr.set(self._lapstr)
def Getsplitb(self):
""" Stop the stopwatch, ignore if stopped. """
if self._running:
self._lapstr = time.time() - self._start
self._setTime(self._elapsedtime)
self.lapbstr.set(self._lapstr)
def Getsplitc(self):
""" Stop the stopwatch, ignore if stopped. """
if self._running:
self._lapstr = time.time() - self._start
self._setTime(self._elapsedtime)
self.lapcstr.set(self._lapstr)
def Getsplitd(self):
""" Stop the stopwatch, ignore if stopped. """
if self._running:
self._lapstr = time.time() - self._start
self._setTime(self._elapsedtime)
self.lapdstr.set(self._lapstr)
def Reset(self):
""" Reset the stopwatch. """
self._start = time.time()
self._elapsedtime = 0.0
self._setTime(self._elapsedtime)
def main():
root = Tk()
sw1 = StopWatch(root)
sw1.pack(side=TOP)
Button(root, text='Start', command=sw1.Start).pack(side=LEFT)
Button(root, text='Stop', command=sw1.Stop).pack(side=LEFT)
Button(root, text='Reset', command=sw1.Reset).pack(side=LEFT)
Button(root, text='Quit', command=root.quit).pack(side=LEFT)
Button(root, text='Get Split A', command=sw1.Getsplita).pack(side=LEFT)
Button(root, text='Get Split B', command=sw1.Getsplitb).pack(side=LEFT)
Button(root, text='Get Split C', command=sw1.Getsplitc).pack(side=LEFT)
Button(root, text='Get Split D', command=sw1.Getsplitd).pack(side=LEFT)
root.mainloop()
if __name__ == '__main__':
main()

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