Python秒表示例-同时启动所有类实例?

Python秒表示例-同时启动所有类实例?,python,tkinter,Python,Tkinter,在本例中,如何同时启动所有4个秒表 这个示例代码已经有12年的历史了,但它是我通过谷歌找到的最好的秒表示例。您可以看到,我有4个类实例在使用中。我需要能够在同一时间启动所有实例。Tinker按钮不允许调用多个函数。即使它做到了,它也将是一个功能先于下一个功能,因此从技术上讲,它们不会完全同时启动 from Tkinter import * import time class StopWatch(Frame): """ Implements a stop watch frame widg

在本例中,如何同时启动所有4个秒表

这个示例代码已经有12年的历史了,但它是我通过谷歌找到的最好的秒表示例。您可以看到,我有4个类实例在使用中。我需要能够在同一时间启动所有实例。Tinker按钮不允许调用多个函数。即使它做到了,它也将是一个功能先于下一个功能,因此从技术上讲,它们不会完全同时启动

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()
我需要在不同的时间停止每个秒表,但这很容易,只要调用类中的每个停止函数即可。但我不知道如何同时启动它们

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

以下程序可能接近您想要的。请注意,由于启动和停止秒表需要时间,因此您可能会发现它们显示的时间之间存在微小差异

#! /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]按钮不允许调用多个函数。”

不,但它可以调用一个函数,而这个函数可以调用多个函数

def start():
    for sw in (sw1, sw2, sw3, sw4):
        sw.Start()

...
Button(root, text='Start', command=start).pack(side=LEFT)
你是对的,不可能同时启动它们。不过,它们之间的距离都在一毫秒或两毫秒之内,所以在大多数情况下,这已经足够好了。由于您仅以整秒钟的粒度显示时间,因此计时器应始终显示相同的时间

如果您确实需要同步它们,则需要它们共享相同的精确开始时间。你可以通过给秒表一个开始时间来完成。然后,您可以计算一次开始时间,并将相同的值传递给所有四个手表:

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)

您还可以拥有一个所有秒表共享的计时器对象。因此,它们与其说是秒表,不如说是“分割计时器”——它们不能控制手表的开始,它们只能记录它们停止的时间间隔

以下是我最后所做的,基于布赖恩的想法,即先创建一个计数器实例,然后进行时间分割。这是可行的,但我还没有找到一种方法,只使用Getspit函数来抓取每一次。也许通过a,b,c,d然后是一个if来获得时间?现在我用按钮来实现,但一旦实现,它将通过我正在编写的主程序中发生的事件来获取它们。如果有人对此有任何改进,请告诉我。谢谢大家的帮助

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

我不确定我是否理解这个问题——为什么不编写一个函数
start\u all
,通过
sw4.start
调用
sw1.start
并将其传递给您的
'start'
按钮呢?@lguananaut我想,因为这样4个实例之间的时间差会很小。不幸的是,对于OP来说,根本没有(非可笑的复杂)的解决方法;如果您只在一个线程中运行,那么一次只能做一件事。然而。。。。在百分之一秒的分辨率下,即使连续启动,4块手表的启动时间也不太可能有明显的差异。我应该说,考虑到当前的实现,没有办法解决这个问题。如果您修改了实现,以便可以为start方法提供开始时间,那么这是可能的;只需捕获按下GUI开始按钮的时间,并将其传递给所有四个
start
方法。如果我在makeWidget中再添加3个标签,那么我将有4个计时器同时启动。布莱恩,你的评论让我重新思考我真正需要什么。我确实需要一个分时计时器。但现在的问题是,如果我这样做,我将如何停止每个计时器(标签):la=label(self,textvariable=self.timestr)la.pack(fill=X,expand=NO,pady=2,padx=2)self.\u elapsedtime)lb=label(self,textvariable=self.timestr)lb.pack(fill=X,expand=NO,pady=2,padx=2)self.\u setTime(self.\u elapsedtime)lc=Label(self,textvariable=self.timestr)lc.pack(fill=X,expand=NO,pady=2,padx=2)self.\u setTime(self.\u elapsedtime)ld=Label(self,textvariable=self.timestr)ld.pack(fill=X,expand=NO,pady=2,padx=2)self.\u setTime(self.\u elapsedtime)“”我只需要停止每个标签在某个时间点更新时间。然后在结束时停止主计时器。然后,我就可以阅读标签,让每个赛车手的时间。