调用Tk()函数实际上是做什么?

21

我正在学习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()

一切都很顺利,直到我注意到Tk类没有被初始化。在其他我找到的在线参考资料中(包括Python库参考effbot.orgTkDocs),通常会调用root = tk.Tk(),然后基于此构建其他示例。同时,我也没有看到任何关于Tk类初始化的参考资料。

我能获取关于Tk类的信息也很模糊,Python参考仅将其列为“顶级窗口小部件...通常是应用程序的主窗口”。最后,如果我替换之前提供的片段中的最后几行:

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

这个程序将像以前一样正常运行。考虑到这一点,我感兴趣的是:

  • root = tk.Tk() 的调用实际上会做什么(即初始化了哪些内容),为什么之前的代码片段可以在没有它的情况下工作?
  • 如果我不调用 Tk() 而只是围绕 Frame 类构建我的应用程序,是否会遇到任何问题或限制?
2个回答

32

Tkinter通过在底层启动一个tcl/tk解释器,然后将tkinter命令转换为tcl/tk命令来工作。主窗口和此解释器是内在相关的,对于tkinter应用程序来说,两者都是必需的。

创建Tk的实例会初始化该解释器并创建根窗口。如果您没有显式地初始化它,则在创建第一个小部件时将隐式创建一个解释器。

我认为不自己初始化没有任何陷阱,但正如Python之禅所述,“明确优于隐含”。如果您显式地创建Tk的实例,您的代码稍微容易理解一些。例如,它将防止其他人询问与您刚刚关于另一个代码提出的同样的问题。


9
Bryan Oakley的回答非常准确。创建小部件将隐式创建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类,它始终被设置为默认的根窗口。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接