Python Tkinter:倒数计时器非常滞后且不准确

Python Tkinter: Countdown Timer is very laggy and not accurate

我在python中使用Tkinter制作了一个倒数计时器,但是非常,秒不是真正的秒(计时器比应该的快)。

tkinter 的 after() 函数并没有完全等待指定的时间量,所以我不能每次使用 after(1) 等待 1 毫秒就减去 1 毫秒,它不会'不准确。所以现在程序找到等待 1ms 时经过的确切时间 after(1) 然后从计时器中减去这个时间。

任何人都可以建议编辑或只是编辑我的程序来解决这些问题吗?

程序如下:


from tkinter import *
import time
import datetime

class root(Tk):
    def __init__(self):
        super(root, self).__init__()

        self.title("Timer")
        
        self.buttonplay = Button(self, text = "Play", fg= 'green', command = self.play)
        self.buttonplay.pack()

        self.buttonpause = Button(self, text = "Pause", fg = "red", command=self.pause)
        self.buttonpause.pack()
        
        self.buttonreset = Button(self, text = "Reset", fg = "red", command=self.reset)
        self.buttonreset.pack()

        self.createTimers()

    def play(self):
        self.timeit=True
        self.timer1.configure(bg='#1C953D')
        self.doTimer()

    def pause(self):
        self.timeit=False
        self.timer1.configure(bg='#454545')
        
    def reset(self):
        self.timer1.destroy()
        self.createTimers()

    def createTimers(self):
        self.total_minute = 1
        self.total_second = 5
        self.total_micros = 0
        self.total = self.total_second + self.total_minute *60 + self.total_micros*0.000001

        self.originalTime = datetime.datetime.now()
        self.micros = self.originalTime.microsecond
        self.seconds = self.originalTime.second
        self.minutes = self.originalTime.minute

        self.time1 = StringVar()
        self.time1.set(str(self.total_minute).rjust(2, '0') + ':' + str(self.total_second).rjust(2, '0') +'.'+ str(self.total_micros)[0:3].rjust(3, '0'))
        self.timer1 = Label(self, textvariable=self.time1, bg='#454545', fg='white', font ="Gadugi 40 bold")
        self.timer1.pack()
        self.timer1.configure(bg='#454545')

    def doTimer(self):
        if (self.total_second + self.total_minute *60 + self.total_micros*0.000001) >0: #Checks if the timer ended
            if self.timeit:
                self.nowTime = datetime.datetime.now()
                self.toDim = self.nowTime.microsecond
                while self.toDim > 0:
                    if self.micros > 0:
                        self.micros = self.micros -1
                        self.toDim = self.toDim -1
                    else:
                        if self.seconds > 0:
                            self.seconds = self.seconds -1
                            self.micros = 999999
                        else:
                            self.minutes = self.minutes -1
                            self.seconds = 59
                self.DimTime = datetime.datetime(self.originalTime.year, self.originalTime.month, self.originalTime.day, self.originalTime.hour, self.minutes, self.seconds, self.micros)
                self.waitMicros = self.originalTime - self.DimTime

                self.total_micros = self.total_micros - self.waitMicros.microseconds
                if self.total_micros <0:
                    self.total_second = self.total_second -1
                    self.total_micros = 999999
                if self.total_second <0:
                    self.total_minute = self.total_minute -1
                    self.total_second = 59


                self.time1.set(str(self.total_minute).rjust(2, '0') + ':' + str(self.total_second).rjust(2, '0') +'.'+ str(self.total_micros)[0:3].rjust(3, '0'))

                self.after(1, self.doTimer)
        else:
            self.time1.set('00:00.000')
            self.timer1.configure(bg='#FF0000')
            self.after(3000, self.reset)


root = root()
root.mainloop()

Here's a video showing the problem.

def play(self):
    self.timeit = True
    self.timer1.configure(bg='#1C953D')

    self.start_time = time.time()
    self.total_start = self.seconds + self.minutes * 60 + self.micros * 0.000001
    self.doTimer()

def pause(self):
    self.timeit = False
    self.timer1.configure(bg='#454545')

def reset(self):
    self.timer1.destroy()
    self.createTimers()

def createTimers(self):
    self.start_time = time.time()
    self.minutes = 1
    self.seconds = 5
    self.micros = 0
    self.total_start = self.seconds + self.minutes * 60 + self.micros * 0.000001

    self.time1 = StringVar()
    self.time1.set(str(self.minutes).rjust(2, '0') + ':' + str(self.seconds).rjust(2, '0') + '.' + str(
        self.micros)[0:3].rjust(3, '0'))
    self.timer1 = Label(self, textvariable=self.time1, bg='#454545', fg='white', font="Gadugi 40 bold")
    self.timer1.pack()
    self.timer1.configure(bg='#454545')

def doTimer(self):
    if (self.seconds + self.minutes * 60 + self.micros * 0.000001) > 0:  # Checks if the timer ended
        if self.timeit:
            self.time_left = self.start_time - time.time() + self.total_start
            self.minutes = int(self.time_left) // 60
            self.seconds = int(self.time_left) % 60
            self.micros = int((self.time_left - int(self.time_left)) * 1000000)
            self.time1.set(
                str(self.minutes).rjust(2, '0') + ':' + str(self.seconds).rjust(2, '0') + '.' + str(
                    self.micros)[0:3].rjust(3, '0'))

        self.after(1, self.doTimer)
    else:
        self.time1.set('00:00.000')
        self.timer1.configure(bg='#FF0000')
        self.after(3000, self.reset)