当试图中断一个 tkinter 应用程序时,似乎 time.sleep() 暂停了之前的一些命令。根据我的理解和以前的经验,label1的text应该设置为“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 文档也没有解决这个问题。
有没有一种简单的方法可以得到明显的预期结果?
最佳答案
time.sleep(...)
不会给出与 after(...)
调用相同的结果。
time.sleep
方法运行,但在第二秒过去之前不显示任何内容。您可以通过在 sleep 调用之前放置 print('before')
来查看这一点。您会看到打印语句在创建窗口前一秒执行。这是因为 Tkinter 在 sleep 期间没有更新任何东西。所以在 sleep 结束之前什么都不会发生,之后标签会立即更新。此外,在 sleep 结束之前不会调用主循环,因此 Tkinter 还不在其主循环中。您可以在 sleep 调用之前使用 self.parent.update()
强制 Tkinter 进行更新。您将看到带有标签 'before'
的窗口显示,等待一秒钟,标签变为 'after'
。然而,在这一秒内窗口没有响应,这就是为什么将 sleep 与 Tkinter 一起使用不是一个好主意。
与 sleep 不同,after 几乎总是更好的选择,因为它立即返回,因此它不会阻止进一步的执行,并安排指定的函数在指定的时间后执行。但是,after 期望传递一个函数名,但是你传递了一个函数调用。这意味着在评估 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 的主循环。
关于python time.sleep() 延迟以前的命令,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28165342/