为什么不鼓励使用多个 Tk 实例?
考虑下面的示例:
import tkinter as tk
root = tk.Tk()
root.title("root")
other_window = tk.Tk()
other_window.title("other_window")
root.mainloop()
另请参阅下面的示例,它连续而不是一次创建 Tk
实例,因此Tk只有一个实例code> 在任何给定时间:
import tkinter as tk
def create_window(window_to_be_closed=None):
if window_to_be_closed:
window_to_be_closed.destroy()
window = tk.Tk()
tk.Button(window, text="Quit", command=lambda arg=window : create_window(arg)).pack()
window.mainloop()
create_window()
- 为什么认为拥有多个
Tk
实例是不好的? - 第二个片段是否被认为更好一点,或者是否受到影响 第一个代码的条件相同吗?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
Tkinter 只是一个嵌入 Tcl 解释器的 Python 包装器,它导入 Tk 库。当您创建根窗口时,您就创建了 Tcl 解释器的实例。
每个 Tcl 解释器都是一个隔离的沙箱。一个沙箱中的对象无法与另一沙箱中的对象交互。最常见的表现是在一个解释器中创建的 StringVar 在另一个解释器中不可见。对于小部件也是如此——您不能在一个解释器中创建在另一解释器中作为父小部件的小部件。图像是第三种情况:在一种情况下创建的图像不能在另一种情况下使用。
从技术角度来看,没有理由不能同时拥有两个
Tk
实例。反对它的建议是因为很少有实际需要有两个或多个不同的 Tcl 解释器,并且它会导致初学者难以掌握的问题。如果不知道您想要实现什么目标,就不可能判断问题中的第二个示例是否更好。它可能也好不了多少,因为您很少会真正需要两个实例。
99.9% 的情况下,最好的解决方案是创建一个在程序生命周期内使用的
Tk
实例。如果您需要第二个或后续窗口,请创建Toplevel
的实例。很简单,这就是 tkinter 和底层 Tcl/Tk 解释器的设计用途。Tkinter is just a python wrapper around an embedded Tcl interpreter that imports the Tk library. When you create a root window, you create an instance of a Tcl interpreter.
Each Tcl interpreter is an isolated sandbox. An object in one sandbox cannot interact with objects in another. The most common manifestation of that is that a
StringVar
created in one interpreter is not visible in another. The same goes for widgets -- you can't create widgets in one interpreter that has as a parent widget in another interpreter. Images are a third case: images created in one cannot be used in another.From a technical standpoint, there's no reason why you can't have two instances of
Tk
at the same time. The recommendation against it is because there's rarely an actual need to have two or more distinct Tcl interpreters, and it causes problems that are hard for beginners to grasp.It's impossible to say whether the second example in the question is better or not without knowing what you're trying to achieve. It probably is not any better since, again, there's rarely ever a time when you actually need two instances.
The best solution 99.9% of the time is to create exactly one instance of
Tk
that you use for the life of your program. If you need a second or subsequent window, create instances ofToplevel
. Quite simply, that is how tkinter and the underlying Tcl/Tk interpreter was designed to be used.我不同意
tkinter
社区不鼓励使用多个tk.Tk
窗口。您可以有多个 tk.Tk 窗口。使用tk.Tk
的多个实例是创建真正彼此独立的窗口的唯一方法。大多数人在创建多个tk.Tk
窗口时犯的唯一错误是他们在创建PhotoImage
时忘记传入master=...
/StringVar
s/IntVar
s/...例如看一下这段代码:
上面的代码不起作用。如果将
master=root2
添加到tk.StringVar()
,那么它将完美地工作。这是因为tkinter
将tk.Tk()
的第一个实例存储在tk._default_root
中。然后,如果您不传入master=...
,它将假定您想要tk._default_root
中的窗口。人们容易犯的另一件事是应该调用
.mainloop()
多少次。它处理来自所有活动tk.Tk
窗口的事件,因此您只需要一个.mainloop()
。对于不同意的人,我会对一个由多个 tk.Tk 窗口引起的实际问题的示例感兴趣。
I disagree with the
tkinter
community discouraging the use of multipletk.Tk
windows. You can have multipletk.Tk
windows. Using multiple instances oftk.Tk
is the only way to create windows that are truly independent of each other. The only mistake most people make when creating multipletk.Tk
windows is that they forget to pass inmaster=...
when creatingPhotoImage
s/StringVar
s/IntVar
s/...For example look at this code:
The code above doesn't work. If you add
master=root2
to thetk.StringVar()
, then it will work perfectly fine. This is becausetkinter
stores the first instance oftk.Tk()
intk._default_root
. Then if you don't pass inmaster=...
, it will assume that you wanted the window intk._default_root
.Another thing people get wrong is how many times should
.mainloop()
be called. It handles events from alltk.Tk
windows that are alive so you only need one.mainloop()
.For folks who disagree, I'd be interested in an example of where an actual problem is caused by the multiple
tk.Tk
windows.到目前为止,我找到的最好的参考是 应用程序窗口 部分href="https://web.archive.org/web/20200715112618id_/http://effbot.org/tkinterbook/" rel="nofollow noreferrer">tkinterbook:
并
我的看法是
Tk
实例创建一个Toplevel
小部件,加上像mainloop
这样的东西,其中应该只有一个。The best reference I've found so far is the Application Windows section of the tkinterbook:
and
My take on it is that a
Tk
instance creates aToplevel
widget, plus things like themainloop
, of which there should be only one.Tk()
初始化隐藏的 tcl 解释器,以便代码可以运行,因为 Tkinter 只是 tcl/tk 的包装器。它还会自动创建一个新窗口。Toplevel()
只是创建一个新窗口,如果Tk()
尚未实例化,则不会工作,因为它需要Tk()< 的 tcl 解释器/code> 初始化。如果不实例化
Tk()
,则无法创建任何 Tkinter 小部件,而 Toplevel 只是一个小部件。在该问题中,您使用Tk()
创建第二个窗口。您应该创建另一个文件,因为多次初始化 tcl 解释器可能会造成混乱,正如 @Bryan Oakley 解释得很好。那么你应该这样做:from os import startfile
startfile(nameOfTheOtherFile)
,因为
Toplevel()
只是一个小部件,它会在Tk()
窗口关闭时关闭。将另一个窗口放在单独的文件中可以减少混乱。Tk()
initializes the hidden tcl interpreter so that the code can run, as Tkinter is just a wrapper around tcl/tk. It also automatically creates a new window.Toplevel()
just creates a new window, and wont work ifTk()
hasn't been instantiated, as it requires the tcl interpreter thatTk()
initializes. You cannot create any Tkinter widgets without instantiatingTk()
, and Toplevel is merely a widget. In the question, you useTk()
to create a second window. You should instead create another file, because initializing the tcl interpreter multiple times can get confusing, as @Bryan Oakley explains so well. Then you should do:from os import startfile
startfile(nameOfTheOtherFile)
, because, as
Toplevel()
is just a widget, it closes when theTk()
window is closed. Having the other window in a separate file makes it less confusing.