【问题标题】:Tkinter app does not update timer smoothlyTkinter 应用程序无法顺利更新计时器
【发布时间】:2020-09-23 03:01:05
【问题描述】:

我对使用 Tkinter 很陌生,我正在尝试构建一个将计时器显示为其功能之一的应用程序。我正在更新标签以显示来自单独线程的时间。显示屏上的时间更新不顺畅。它会在短时间内冻结,然后跳跃一秒钟或更长时间。有没有办法让更新保持一致以使计时器顺畅?

到目前为止,这是一个简单的应用程序,因此 CPU 或主线程似乎不应该忙于做其他事情。当您按下按钮时,它会启动一个单独的线程,该线程会定期设置标签文本。我试过每次更新睡 0-0.1 秒,结果是一样的。

window = tk.Tk()
frame2 = tk.Frame(master=window, width=50, height=50, bg="yellow")
frame2.pack()

time_display = tk.Label(master=frame2, text="0.0")
time_display.pack()

update_thread = None


def play_pause():
    global update_thread, stop_loop
    if not update_thread:
        stop_loop = False
        update_thread = threading.Thread(target=update_timer_loop)
        update_thread.start()
    else:
        stop_loop = True
        update_thread = None


stop_loop = False

def update_timer_loop():
    global window
    start = time.time()
    base_time = float(time_display["text"])
    while not stop_loop:
        current_time = time.time() - start + base_time
        window.after(0, lambda: set_text(round(current_time, 2)))
        time.sleep(0.1)


def set_text(text):
    time_display["text"] = text

btn_play = tk.Button(master=frame1, text="Play/Pause", command=play_pause)
btn_play.pack(side=tk.LEFT)

【问题讨论】:

    标签: python tkinter


    【解决方案1】:

    你根本不需要线程。我看到您尝试使用 after,这是正确的方法。唯一需要知道的是,您可以使用after_cancel 取消您使用after 安排的即将举行的活动。试试这个:

    import tkinter as tk
    import time
    
    window = tk.Tk()
    
    time_display = tk.Label(window, text="0.0")
    time_display.pack()
    
    update_thread = None
    
    def play_pause():
        global update_thread, start, base_time
        if update_thread is None:
            start = time.time()
            base_time = float(time_display["text"])
            update_timer_loop() # start the loop
        else:
            time_display.after_cancel(update_thread)
            update_thread = None
    
    def update_timer_loop():
        global update_thread
        current_time = time.time() - start + base_time
        time_display["text"] = round(current_time, 2)
        update_thread = window.after(100, update_timer_loop)
    
    btn_play = tk.Button(master=window, text="Play/Pause", command=play_pause)
    btn_play.pack(side=tk.LEFT)
    
    window.mainloop()
    

    【讨论】:

    • 这并不能解决问题。这仅与停止计时器和取消任何挂起的更新有关。在我尝试停止它之前,它没有跟上更新。
    • 对不起,你能解释一下你跟上更新的意思吗?据我所知,它的工作原理与您的示例完全一样(只是顺利)。
    • 如果后台线程在每个循环中休眠 0.1 秒,那么它应该每十分之一秒显示一次。除了它会从 2 秒跳到 4 秒,然后跳到 5 秒,例如。
    • 你试过我的代码了吗?它每 0.1 秒更新一次显示。
    • 是的,刚刚试过。它确实工作得更好。我想这只是导致问题的背景循环。似乎四核计算机应该能够同时运行 2 个线程。
    猜你喜欢
    • 2017-09-17
    • 2016-12-03
    • 1970-01-01
    • 2018-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-04
    相关资源
    最近更新 更多