【问题标题】:Unable to destroy a Tk object from inside its widget's callback无法从其小部件的回调中销毁 Tk 对象
【发布时间】: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 ... 完成?":你不能,作为callbacktkinter.mainloop() 的一部分,它必须对.destroy() 进行cleanup。您必须使用Threadmainloop 解除绑定
  • @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


【解决方案1】:

好的,感谢@martineau 的指点,我找到了一个解决方案——一个非常简单的解决方案。每当我希望对该对象的任何更改生效时,我都会从 Toplevel 对象调用方法 update()。即使前面的更改正在破坏这个对象,这仍然有效。感谢所有提供他们的 cmets 和反馈的人。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-12-25
    • 1970-01-01
    • 1970-01-01
    • 2010-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多