Recipe 11.8. Implementing a Stopwatch in Tkinter
Credit: JØrgen Cederberg, Tobias
Klausmann
Problem
You are coding an application in Tkinter
and need a widget that implements a stopwatch.
Solution
Implementing a new widget is almost always best done by subclassing
Frame:
from Tkinter import *
import time
class StopWatch(Frame):
"" Implements a stop watch frame widget. ""
msec = 50
def _ _init_ _(self, parent=None, **kw):
Frame._ _init_ _(self, parent, kw)
self._start = 0.0
self._elapsedtime = 0.0
self._running = False
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(self.msec, self._update)
def _setTime(self, elap):
"" Set the time string to Minutes:Seconds:Hundredths ""
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 already running. ""
if not self._running:
self._start = time.time( ) - self._elapsedtime
self._update( )
self._running = True
def Stop(self):
"" Stop the stopwatch, ignore if already stopped. ""
if self._running:
self.after_cancel(self._timer)
self._elapsedtime = time.time( ) - self._start
self._setTime(self._elapsedtime)
self._running = False
def Reset(self):
"" Reset the stopwatch. ""
self._start = time.time( )
self._elapsedtime = 0.0
self._setTime(self._elapsedtime)
Discussion
Here is an example of use of this StopWatch widget,
presented, as usual, with a guard of if _ _name_ _ == '_
_main_ _' so we can make it part of the module containing
the class and have it run when the module is executed as a
"main script":
if _ _name_ _ == '_ _main_ _':You might want to use time.clock instead of
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( )
main( )
time.time if your stopwatch's
purpose is to measure the amount of CPU time that your program is
taking, rather than the amount of elapsed time. I used
time.time, without even bothering to make that
choice easily customizable (you'll need to edit its
several appearances in the recipe's code), because
it seems the most natural choice to me by far. One aspect that you
can customize easily, by subclassing and data overriding or simply by
setting the msec instance attribute on a particular
StopWatch instance, is how often the time display is
updated onscreen; the default of 50 milliseconds, which translates to
20 updates a second, may well mean updates that are too frequent for
your purposes, although they suit my own just fine.
See Also
Docs about the time module in the
Library Reference and Python in a
Nutshell; information about Tkinter can be obtained from
a variety of sources, such as Fredrik Lundh, An
Introduction to Tkinter (PythonWare: http://www.pythonware.com/library), New
Mexico Tech's Tkinter
Reference (http://www.nmt.edu/tcc/help/lang/python/docsl),
Python in a Nutshell, and various other books.