为何Tkinter第一个窗口需调用mainloop(),第二个无需调用?
mainloop()也能正常运行? 这事儿得从tkinter底层的Tcl解释器和事件循环机制说起,我给你唠明白:
主事件循环会接管所有Tk实例的事件:你代码里第一个
tk.Tk()实例(也就是Bridge类里的self.root)启动的mainloop(),其实是整个Python进程里的主事件循环。当你再创建第二个tk.Tk()实例时,虽然它会初始化一个独立的Tcl解释器,但主事件循环会自动轮询所有活跃的Tcl解释器的事件队列——也就是说,第二个窗口的显示、交互等事件,都会被主循环处理,根本不需要自己再启动mainloop()。update()方法帮你提前触发了事件处理:你在check()方法里调用了self.master.update(),这个方法会强制刷新第二个窗口的事件队列,把所有待处理的事件(比如窗口显示的请求)立刻处理掉。这就保证了第二个窗口能马上显示出来,不用等主循环慢悠悠地轮到它。就算你给第二个窗口加上self.master.mainloop(),它也能跑,但这其实是启动了第二个事件循环,虽然在你的代码里没出问题,但这种写法非常不推荐——多个Tk实例+多个事件循环很容易搞出各种奇怪的bug,比如窗口卡死、响应延迟、内存泄漏之类的。正经的多窗口写法应该用
Toplevel:tkinter官方最推荐的多窗口方案是用tk.Toplevel(),而不是创建多个tk.Tk()。Toplevel窗口会依附于主Tk窗口,共享同一个事件循环,代码更干净,也不会有那些莫名其妙的问题。给你改个示例:
class DecompilingChecker(object): def __init__(self, parent): # 用Toplevel关联主窗口 self.master = tk.Toplevel(parent) self.master.title("Test Program: Update") # 如果需要一开始隐藏窗口,可以加这句:self.master.withdraw() def check(self, file, directory): # 如果之前隐藏了,现在显示出来 self.master.deiconify()
然后在GUI的初始化里传主窗口进去:
self.decompilingchecker = DecompilingChecker(self.master)
这样改完,就完全不用纠结多个事件循环的问题了。
内容的提问来源于stack exchange,提问作者Unsigned_Arduino

