【发布时间】:2019-12-14 07:57:42
【问题描述】:
[已编辑] 我正在尝试从其小部件的回调中销毁 Toplevel 对象,但似乎在回调函数完成运行之前无法销毁它。以下是我的脚本的精髓:
from tkinter import *
from time import sleep
import gnupg
w = Tk()
t = Toplevel()
lbl = Label(t, text="blah blah")
lbl.grid(row=0, column=0)
lbl.bind("<Button-1>", func_a)
def func_a(event):
event.widget.master.destroy()
gpg = gnupg.GPG()
plaindata = b'Some data'
encrdata = plaindata
for i in range(20):
encrdata = gpg.encrypt(encrdata,
symmetric=True,
passphrase='something',
recipients=None).data
print("func_a is done")
w.mainloop()
如您所见,我使用 gpg 对称加密 20 次,大约需要 20 秒。单击标签(对象“lbl”)时,我期望看到的是整个顶层窗口(对象“t”)立即消失,然后 20 秒后消息“func_a is gone”在终端中打印。相反,Toplevel 窗口在 20 秒内没有响应(我仍然可以移动它,但它的所有小部件都冻结了),然后在打印上述消息的同时最终消失。
您能否解释一下为什么父级 Toplevel 没有立即被销毁?它与被称为小部件回调的函数有关吗?以及如何在回调函数中的其他内容完成之前强制杀死父窗口?
【问题讨论】:
-
为什么不只是
sleep(20)而不是重复sleep(1)20 次? -
对
sleep()的重复调用阻止了mainloop()的执行。请致电event.widget.master.update_idletasks()。此外,如果您想延迟 tkinter 应用程序,请改用通用小部件方法after()。 -
"parent
window.destroy()before ... callback ... 完成?":你不能,作为callback是tkinter.mainloop()的一部分,它必须对.destroy()进行cleanup。您必须使用Thread从mainloop解除绑定。 -
@martineau 也许我没有解释清楚。这只是一个复制问题的简单测试用例。在我的真实脚本中,我使用了一些没有 sleep() 但仍需要时间才能完成的循环。假设我多次对内容进行哈希处理,并且需要 10-15 秒才能完成。在它完成之前,父窗口不能被破坏甚至修改——它只是在那里冻结 10-15 秒。这就是问题所在。
-
这一切都不会改变我所说的——当
mainloop()在 tkinter 应用程序中运行时,一切都必须发生,否则它将冻结。请参阅我对问题的回答Freezing/Hanging tkinter Gui in waiting for the thread to complete。
标签: python python-3.x tkinter callback tk