调用Tk()到底做了什么?
我在复习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()
这个示例看起来不错,但我注意到没有初始化root = tk.Tk()
,后面的示例都是基于这个的。我在NMT的参考资料中也没有看到关于
关于
root = tk.Tk()
app = Application(root)
这个程序运行的效果和之前一样。考虑到这些,我想知道的是:
- 调用
root = tk.Tk()
到底做了什么(也就是说,初始化了什么),为什么之前的示例可以在没有它的情况下运行? - 如果我不调用
(),而是直接围绕 Frame
类构建我的应用程序,会遇到什么问题或限制吗?
2 个回答
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
类是如何初始化的,它总是会被设置为默认根。
Tkinter 是通过在后台启动一个 tcl/tk 解释器来工作的,然后把 tkinter 的命令转换成 tcl/tk 的命令。主窗口和这个解释器是紧密相连的,两个都是 tkinter 应用程序正常运行所必需的。
创建一个 Tk
的实例会初始化这个解释器,并创建根窗口。如果你不自己明确地初始化它,当你创建第一个小部件时,系统会自动为你创建一个。
我觉得不自己初始化也没什么大问题,但正如 Python 的哲学所说,“明确总比隐含好”。如果你明确地创建 Tk
的实例,你的代码会稍微容易理解一些。这样,其他人就不会像你刚才问的那样,对你的代码产生同样的问题了。