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

3
我用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()
1个回答

2
我不知道它是否这样做是因为时钟代码需要额外的时间来执行。
在这种情况下,你是正确的,你的计时器速度取决于代码的运行时间。因此,让这个脚本从你的电脑中获取更多资源也会减慢计时器的速度,反之亦然。
“不要重复发明轮子。”——编程谚语。
使用“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()


谢谢 @LBJ 提供的答案,您能否向我解释如何使用 time 模块制作倒计时器?我没有找到任何使用此模块的计时器。 - The_Fishy
1
@The_Fishy的帖子已更新。 - LBJ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接