为什么不鼓励使用多个 Tk 实例?

发布于 2025-01-14 05:12:16 字数 681 浏览 1 评论 0 原文

考虑下面的示例:

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 实例是不好的?
  • 第二个片段是否被认为更好一点,或者是否受到影响 第一个代码的条件相同吗?

Consider below example:

import tkinter as tk

root = tk.Tk()
root.title("root")

other_window = tk.Tk()
other_window.title("other_window")

root.mainloop()

and also see below example that creates instances of Tk back-to-back instead of at once, so there's exactly one instance of Tk at any given time:

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()
  • Why is it considered bad to have multiple instances of Tk?
  • Is the second snippet considered a bit better, or does it suffer from
    the same conditions the first code does?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

十年九夏 2025-01-21 05:12:16

为什么认为拥有多个 Tk 实例是不好的?

Tkinter 只是一个嵌入 Tcl 解释器的 Python 包装器,它导入 Tk 库。当您创建根窗口时,您就创建了 Tcl 解释器的实例。

每个 Tcl 解释器都是一个隔离的沙箱。一个沙箱中的对象无法与另一沙箱中的对象交互。最常见的表现是在一个解释器中创建的 StringVar 在另一个解释器中不可见。对于小部件也是如此——您不能在一个解释器中创建在另一解释器中作为父小部件的小部件。图像是第三种情况:在一种情况下创建的图像不能在另一种情况下使用。

从技术角度来看,没有理由不能同时拥有两个 Tk 实例。反对它的建议是因为很少有实际需要有两个或多个不同的 Tcl 解释器,并且它会导致初学者难以掌握的问题。

第二个代码片段是否被认为更好一点,或者它是否遇到与第一个代码相同的条件?

如果不知道您想要实现什么目标,就不可能判断问题中的第二个示例是否更好。它可能也好不了多少,因为您很少会真正需要两个实例。

99.9% 的情况下,最好的解决方案是创建一个在程序生命周期内使用的 Tk 实例。如果您需要第二个或后续窗口,请创建 Toplevel 的实例。很简单,这就是 tkinter 和底层 Tcl/Tk 解释器的设计用途。

Why is it considered bad to have multiple instances of 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.

Is the second snippet considered a bit better, or does it suffer from the same conditions the first code does?

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 of Toplevel. Quite simply, that is how tkinter and the underlying Tcl/Tk interpreter was designed to be used.

℉服软 2025-01-21 05:12:16

我不同意 tkinter 社区不鼓励使用多个 tk.Tk 窗口。您可以有多个 tk.Tk 窗口。使用 tk.Tk 的多个实例是创建真正彼此独立的窗口的唯一方法。大多数人在创建多个 tk.Tk 窗口时犯的唯一错误是他们在创建 PhotoImage 时忘记传入 master=... /StringVars/IntVars/...

例如看一下这段代码:

import tkinter as tk

root = tk.Tk()
root2 = tk.Tk()

variable = tk.StringVar() # Add `master=root2` to fix the problem
entry = tk.Entry(root2, textvariable=variable)
entry.bind("<Return>", lambda e: print(repr(variable.get())))
entry.pack()

root.mainloop()

上面的代码不起作用。如果将 master=root2 添加到 tk.StringVar(),那么它将完美地工作。这是因为 tkintertk.Tk() 的第一个实例存储在 tk._default_root 中。然后,如果您不传入 master=...,它将假定您想要 tk._default_root 中的窗口。


人们容易犯的另一件事是应该调用.mainloop() 多少次。它处理来自所有活动 tk.Tk 窗口的事件,因此您只需要一个 .mainloop()

对于不同意的人,我会对一个由多个 tk.Tk 窗口引起的实际问题的示例感兴趣。

I disagree with the tkinter community discouraging the use of multiple tk.Tk windows. You can have multiple tk.Tk windows. Using multiple instances of tk.Tk is the only way to create windows that are truly independent of each other. The only mistake most people make when creating multiple tk.Tk windows is that they forget to pass in master=... when creating PhotoImages/StringVars/IntVars/...

For example look at this code:

import tkinter as tk

root = tk.Tk()
root2 = tk.Tk()

variable = tk.StringVar() # Add `master=root2` to fix the problem
entry = tk.Entry(root2, textvariable=variable)
entry.bind("<Return>", lambda e: print(repr(variable.get())))
entry.pack()

root.mainloop()

The code above doesn't work. If you add master=root2 to the tk.StringVar(), then it will work perfectly fine. This is because tkinter stores the first instance of tk.Tk() in tk._default_root. Then if you don't pass in master=..., it will assume that you wanted the window in tk._default_root.


Another thing people get wrong is how many times should .mainloop() be called. It handles events from all tk.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.

生来就爱笑 2025-01-21 05:12:16

到目前为止,我找到的最好的参考是 应用程序窗口 部分href="https://web.archive.org/web/20200715112618id_/http://effbot.org/tkinterbook/" rel="nofollow noreferrer">tkinterbook:

在我们到目前为止使用的简单示例中,屏幕上只有一个窗口;根窗口。当您调用 Tk 构造函数

时,它会自动创建

如果您需要创建其他窗口,可以使用Toplevel小部件。它只是在屏幕上创建一个新窗口,该窗口的外观和行为与原始根窗口非常相似

我的看法是 Tk 实例创建一个 Toplevel 小部件,加上像 mainloop 这样的东西,其中应该只有一个。

The best reference I've found so far is the Application Windows section of the tkinterbook:

In the simple examples we’ve used this far, there’s only one window on the screen; the root window. This is automatically created when you call the Tk constructor

and

If you need to create additional windows, you can use the Toplevel widget. It simply creates a new window on the screen, a window that looks and behaves pretty much like the original root window

My take on it is that a Tk instance creates a Toplevel widget, plus things like the mainloop, of which there should be only one.

柒夜笙歌凉 2025-01-21 05:12:16

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 if Tk() hasn't been instantiated, as it requires the tcl interpreter that Tk() initializes. You cannot create any Tkinter widgets without instantiating Tk(), and Toplevel is merely a widget. In the question, you use Tk() 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 the Tk() window is closed. Having the other window in a separate file makes it less confusing.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文