调用Tk()到底做了什么?

21 投票
2 回答
49491 浏览
提问于 2025-04-18 13:11

我在复习Tkinter的时候,看到一个来自NMT Tkinter 8.5参考的简单示例。

#!/usr/bin/env python
import tkinter as tk

class Application(tk.Frame):    
    def __init__(self, master=None):    
        tk.Frame.__init__(self, master)
        self.grid()
        self.createWidgets()

    def createWidgets(self):    
        self.quitButton = tk.Button(self, text='Quit',command=self.quit)
        self.quitButton.grid()

app = Application()
app.master.title('Sample application')
app.mainloop()

这个示例看起来不错,但我注意到没有初始化类。在我找到的其他在线参考资料中(比如Python的库参考effbot.orgTkDocs),通常都会有一行代码是root = tk.Tk(),后面的示例都是基于这个的。我在NMT的参考资料中也没有看到关于类初始化的任何说明。

关于类的信息也很模糊,Python参考资料只把它描述为“顶层小部件……通常是应用程序的主窗口”。最后,如果我把之前示例的最后几行替换成:

root = tk.Tk()
app = Application(root)

这个程序运行的效果和之前一样。考虑到这些,我想知道的是:

  • 调用root = tk.Tk()到底做了什么(也就是说,初始化了什么),为什么之前的示例可以在没有它的情况下运行?
  • 如果我不调用(),而是直接围绕Frame类构建我的应用程序,会遇到什么问题或限制吗?

2 个回答

9

Bryan Oakley 的回答非常准确。创建一个小部件(widget)会自动创建一个tcl/tk解释器的实例。不过,我想补充一些代码片段,帮助大家更好地理解Tk是如何被自动创建的。

每当创建一个Widget对象(无论是Frame、Button还是基于ttk的小部件),都会调用BaseWidget类的__init__方法,而这个方法又会调用_setup方法。下面是相关部分的代码片段:

def _setup(self, master, cnf):
    """Internal function. Sets up information about children."""
    if _support_default_root:
        global _default_root
        if not master:
            if not _default_root:
                _default_root = Tk()
            master = _default_root
    self.master = master
    self.tk = master.tk

这里的_support_default_root_default_root是全局变量,它们在tkinter包的__init__.py文件的第132-133行被声明。它们被初始化为以下值:

_support_default_root = 1
_default_root = None

这意味着,如果没有提供master,并且之前没有创建解释器,那么就会创建一个Tk的实例,并将其作为所有未来小部件的默认根。

在创建Tk类的实例时,还有一些有趣的事情。以下代码片段来自Tk._loadtk方法:

if _support_default_root and not _default_root:
    _default_root = self

这意味着,无论Tk类是如何初始化的,它总是会被设置为默认根。

33

Tkinter 是通过在后台启动一个 tcl/tk 解释器来工作的,然后把 tkinter 的命令转换成 tcl/tk 的命令。主窗口和这个解释器是紧密相连的,两个都是 tkinter 应用程序正常运行所必需的。

创建一个 Tk 的实例会初始化这个解释器,并创建根窗口。如果你不自己明确地初始化它,当你创建第一个小部件时,系统会自动为你创建一个。

我觉得不自己初始化也没什么大问题,但正如 Python 的哲学所说,“明确总比隐含好”。如果你明确地创建 Tk 的实例,你的代码会稍微容易理解一些。这样,其他人就不会像你刚才问的那样,对你的代码产生同样的问题了。

撰写回答