这个错误是由一个应用程序中有多个Tk 实例引起的。 tkinter 应用程序中应该始终只有一个 Tk 实例。如果要创建辅助窗口,请使用Toplevel 代替Tk。
但您会注意到,如果您确实将 load = Tk 替换为 load = Toplevel,load 根本不会显示。在tkinter 应用程序中使用线程时,最好将所有tkinter 内容保留在一个线程中。如果您将任何tkinter 小部件或操作拆分为单独的线程,则可能会导致问题。您应该将for 循环放入load() 中,并将当前位于load() 中的所有内容放入for 循环所在的位置。这可以防止任何tkinter 函数调用或小部件创建发生在两个不同的线程中。
第三,我强烈建议您不要在这样的循环中定义变量。在创建变量后尝试访问变量时会很麻烦,而且速度很慢。对于这么多数字,您可以创建一个列表并将数字附加到列表中。在我的示例中,该列表称为numbers。
第四,您需要在load 函数中使用global,以便loading 变量可以在线程中正确使用。您还有两个名为load 的变量:函数和窗口。您应该重命名其中一个,以免其中一个遮盖另一个。在我的示例中,我将窗口重命名为 load 为 load_window。
要使Toplevel 显示在顶部,您可以设置load_window.wm_attributes("-topmost", True)。
下面是代码的样子:
from tkinter import *
# import time # Uncomment this to show the loading window for a little longer
from threading import Thread
loaded = False
numbers = []
def load():
global loaded, numbers
# Add the numbers to the list
numbers = [x for x in range(0, 720)]
# time.sleep(1) # Uncomment this to show the loading window for a little bit longer
loaded = True
root = Tk()
load_window = Toplevel(root)
Label(load_window, text = "Loading...").pack()
t = Thread(target = load)
t.start()
def check():
global loaded, load_window
if loaded:
load_window.destroy()
else:
load_window.after(1, check)
check()
load_window.wm_attributes("-topmost", True)
load_window.mainloop()
root.mainloop()
请注意,当您运行代码时,您会得到一个_tkinter.TclError:
Traceback (most recent call last):
File "/home/user/test.py", line 29, in <module>
load_window.wm_attributes("-topmost", True)
File "/usr/lib/python3.8/tkinter/__init__.py", line 1976, in wm_attributes
return self.tk.call(args)
_tkinter.TclError: bad window path name ".!toplevel"
这是因为load() 运行速度如此之快,以至于它在设置-topmost 之前就破坏了loaded_window。您可能知道,在被破坏的小部件上调用函数会引发错误。因此,只有更高的数字才真正需要整个加载窗口。即使我使用range(0, 900000) 而不是range(0, 720),代码也会运行,但它仍然如此之快,以至于你只看到load_window 一瞬间。
如果您仍想看到加载窗口,可以取消注释import time 和time.sleep(... 行,这将导致load_window 在关闭前等待一秒钟。