Python stopwatch example - starting all class instances at the same time?
Question: 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()
    


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

