python time.sleep() 延迟之前的命令

python time.sleep() delays previous commands

当试图中断一个 tkinter 应用程序时,time.sleep() 似乎搁置了一些先前的命令。根据我的理解和以前的经验,label1的text应该设置成"before"一秒,然后改成"after"。但是,"before" 值永远不会出现,"after" 在执行后一秒正常打印。

from tkinter import *
import time
class Display(Frame):
    def __init__(self, parent):
        Frame.__init__(self, parent)
        self.parent = parent
        label1 = Label(text = "before")
        label1.grid()
        self.after(1000, label1.config(text = "after"))

def main():
    root = Tk()
    Display(root)
    root.mainloop()

if __name__ == '__main__':
    main()

请注意,使用 time.sleep(...) 产生与 tkinter after(...)

相同的结果
from tkinter import *
import time
class Display(Frame):
    def __init__(self, parent):
        Frame.__init__(self, parent)
        self.parent = parent
        label1 = Label(text = "before")
        label1.grid()
        time.sleep(1)
        label1.config(text = "after")

def main():
    root = Tk()
    Display(root)
    root.mainloop()

if __name__ == '__main__':
    main()

我想 tkinter 正在等待执行图形工作的东西(控制台没有问题)但我没有看到什么并且 tkinter 文档没有解决这个问题。
有没有一种简单的方法可以得到明显的预期结果?

没用也就不足为奇了。想一想 Tk 框架在做什么:它正在创建您的 windows、display = Display(),然后线程停止。对象未完全创建。您是否希望 Tk 渲染一个通过其构造函数进行到一半的对象?

首先,尝试将所有与线程相关的代码移出构造函数。应该允许构造函数正常完成,线程代码应该在另一个函数中。

其次,在正常逻辑中间使用 thread.sleep 是不好的做法。通常,您启动一​​个单独的线程,该线程可以根据需要等待和休眠。 (虽然不知道Tk有没有特殊的处理方式。)

time.sleep(...) 给出的结果与 after(...) 调用的结果不同。

time.sleep 方法 运行s,但在第二个过去之前没有显示任何内容。您可以通过在睡眠呼叫之前放置 print('before') 来查看。您会看到打印语句在创建 window 前一秒执行。这是因为 Tkinter 在睡眠期间没有更新任何东西。所以在睡眠结束之前什么都不会发生,之后标签会立即更新。此外,在睡眠结束之前不会调用主循环,因此 Tkinter 还不在其主循环中。您可以在睡眠呼叫之前使用 self.parent.update() 强制 Tkinter 进行更新。您将看到 window 显示,标签为 'before',等待一秒钟,标签变为 'after'。然而,在这一秒内 window 没有响应,这就是为什么将睡眠与 Tkinter 一起使用是一个坏主意。

after 几乎总是更好的选择,因为它 return 立即执行,因此它不会阻止进一步的执行,并安排指定的函数在指定的时间后执行,而不是睡眠。但是,after 期望传递一个函数名,但是你传递了一个函数调用。这意味着在评估 after 调用时,函数是 运行 并且 return 值(即 None)作为函数名称传递。因此,您会看到标签在 window 打开时发生了更改,因为更改是在评估后调用时进行的。您应该做的是将函数名称传递给 after:

def update_label:
    label1.config(text = "after")

self.after(1000, update_label)

或更短,通过创建一个匿名函数:

self.after(1000, lambda: label1.config(text = "after"))

这会给你显示带有 'before' 的标签的预期结果,它会在一秒钟后变为 'after',而不会阻塞 Tkinter 的主循环。