调用 Tk() 实际上做了啥?

Posted

技术标签:

【中文标题】调用 Tk() 实际上做了啥?【英文标题】:What does calling Tk() actually do?调用 Tk() 实际上做了什么? 【发布时间】:2014-09-03 22:21:55 【问题描述】:

当我查看NMT Tkinter 8.5 Reference 中的一个最小示例时,我正在复习 Tkinter。

#!/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's Library Reference、effbot.org、TkDocs)中,通常会调用root = tk.Tk(),其余的示例都以此为基础。我也没有在 NMT 的引用中看到任何对 Tk 类初始化的引用。

我可以获得的关于Tk 类的信息也很模糊,Python 参考仅将其列为“***小部件......通常是应用程序的主窗口”。最后,如果我替换之前介绍的 sn-p 中的最后几行:

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

程序会像以前一样运行。考虑到这一切,我想知道的是:

调用root = tk.Tk() 的实际作用是什么(例如,初始化了什么)以及为什么没有它之前的 sn-p 可以工作? 如果我不调用Tk() 而只是围绕Frame 类构建我的应用程序,我会遇到任何陷阱或限制吗?

【问题讨论】:

【参考方案1】:

Bryan Oakley's 答案很准确。创建一个小部件将隐式创建一个 tcl/tk 解释器的实例。不过,我想添加一些代码,以更好地了解 Tk 是如何隐式创建的。

无论何时创建一个 Widget 对象(无论是 Frame 或 Button 甚至是基于 ttk 的小部件),都会调用 BaseWidget 类的 __init__ 方法,然后调用 _setup 方法。这是相关部分的sn-p:

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 类的实例时还有一些有趣的事情。以下sn-p来自Tk._loadtk方法:

if _support_default_root and not _default_root:
    _default_root = self

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

【讨论】:

【参考方案2】:

Tkinter 的工作原理是在后台启动一个 tcl/tk 解释器,然后将 tkinter 命令翻译成 tcl/tk 命令。主窗口和这个解释器是内在联系的,两者都是 tkinter 应用程序工作所必需的。

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

我认为不自己初始化它不会有任何陷阱,但正如 python 禅宗所说,“显式优于隐式”。如果您显式创建Tk 的实例,您的代码将更容易理解。例如,它会阻止其他人就您的代码提出与您刚刚询问的其他代码相同的问题。

【讨论】:

以上是关于调用 Tk() 实际上做了啥?的主要内容,如果未能解决你的问题,请参考以下文章

React Hooks - 引擎盖下发生了啥?

纤维/未来实际上做了啥?

标准“安装”实际上做了啥?

strdup() - 它在 C 中做了啥?

[].forEach.call() 在 JavaScript 中做了啥?

扩展“jsx”究竟做了啥? [复制]