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

时间:2015-01-27 07:30:17

标签: python time tkinter sleep

当试图中断tkinter应用程序时,似乎time.sleep()将一些先前的命令置于保持状态。根据我的理解和以前的经验,label1的文本应设置为“之前”一秒钟,然后更改为“之后”。但是,“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相同的结果

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 doc没有解决这个问题。
是否有一种简单的方法可以获得明显的预期结果?

2 个答案:

答案 0 :(得分:5)

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

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

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

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

self.after(1000, update_label)

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

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

这将为您显示带有'before'的标签的预期结果,该标签在一秒钟后更改为'after',而不会阻止Tkinter的主循环。

答案 1 :(得分:0)

不起作用并不奇怪。想想Tk框架正在做什么:它正在创建你的窗口,display = Display(),并且在那一刻线程停止。该对象未完全创建。你是否希望Tk渲染一个通过其构造函数一半的对象?

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

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