Python tkinter:倒计时计时器不准确



我在python中使用Tkinter制作了一个倒计时计时器,但我唯一的问题是计时器中的一秒比实际的一秒长一点。

我使用after()函数,每隔一毫秒,从时钟中删除一毫秒(0.001秒)。

我不知道它是否在这样做因为时钟的代码需要一些额外的时间来执行,如果是这样的话,我如何用完全相同的UI制作一个时钟,执行时间更少?

这是展示问题的视频

程序:

from tkinter import *
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.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.minute = 0
self.second = 5
self.ms = 0
self.total = self.second + self.minute *60 + self.ms*0.001
self.time1 = StringVar()
self.time1.set(str(self.minute).rjust(2, '0') + ':' + str(self.second).rjust(2, '0') +'.'+ str(self.ms).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):
self.time = self.second + self.minute *60 + self.ms*0.001
if self.time !=0: #Checks if the timer ended
if self.timeit:
self.timer1.configure(bg='#1C953D')

self.ms = self.ms -1
if self.ms <0:
self.second = self.second -1
self.ms = 999
if self.second == -1:
self.minute = self.minute -1
self.second = 59
self.time1.set(str(self.minute).rjust(2, '0') + ':' + str(self.second).rjust(2, '0') +'.'+ str(self.ms).rjust(3, '0'))

if self.timeit:
self.after(1, self.doTimer)
else:
self.ended = 1
self.timer1.configure(bg='#FF0000')
self.after(3000, self.reset)

root = root()
root.mainloop()

我不知道它是否在这样做,因为时钟的代码需要一些额外的时间来执行

在这种情况下,您是对的,计时器的节奏取决于代码的运行时。因此,让这个脚本需要更多的计算机资源也会减慢计时器,反之亦然。

"不要重新发明轮子"。——编程格言。

使用time模块在计时器中获得更准确的时间。更具体地说,time.time()并将其格式化以使其可读。

编辑:

这里有一个例子来说明你的问题。

import time
time_zone = 0 # UTC
while True:
current_time = time.time()
ms = (current_time * 1000) % 1000
s = (current_time % 60)
m = (current_time % (60*60))//60
h = (current_time % (60*60*24))//(60*60)
print(f"h:{int(h+time_zone)} - m:{int(m)} - s:{int(s)} - ms:{int(ms)}")
time.sleep(1)

理论上,这个脚本应该每秒钟精确地打印时间。但是,由于代码运行时的原因,会增加几个毫秒。去除time.sleep(1)应该会让你非常接近一个活时钟。

所以如果你想要一个接近计时器或秒表的东西,你得到当前纪元时间的时间戳(time.time())更新你的计时器大约每x个滴答每秒得到计数毫秒的效果,当按钮再次按下时,你得到一个新的时间戳,然后你比较它与第一个时间戳并减去得到每个按钮按下之间的确切时间。


我已经为你做了一个模板来修补一下:

import tkinter as tk
import time
time_zone = 0  # UTC
# Convert epoch time to readable format
def readable_epoch(time_epoch):
ms = (time_epoch * 1000) % 1000
s = (time_epoch % 60)
m = (time_epoch % (60*60))//60
h = (time_epoch % (60*60*24))//(60*60)
return (h, m, s, ms)

class App(tk.Tk):
def __init__(self):
super().__init__()
self.time1 = 0
self.time2 = 0
self.geometry("300x200")
self.button1 = tk.Button(
self, text="Click me first", command=self.button1, bg="teal")
self.button1.pack(ipadx=10, ipady=10, expand=True, side=tk.LEFT)
self.button2 = tk.Button(
self, text="Click me second", command=self.button2, bg="pink")
self.button2.pack(ipadx=10, ipady=10, expand=True, side=tk.LEFT)
# Get current time
def button1(self):
self.current_time = time.time()
h, m, s, ms = readable_epoch(self.current_time)
print(f"h:{int(h+time_zone)}, m:{int(m)}, s:{int(s)}, ms:{int(ms)}")
# Elapsed time since button 1 was pressed:
def button2(self):
new_time = time.time()
new_time = new_time - self.current_time
h, m, s, ms = readable_epoch(new_time)
print(f"h:{int(h+time_zone)}, m:{int(m)}, s:{int(s)}, ms:{int(ms)}")

if __name__ == "__main__":
app = App()
app.mainloop()

最新更新