当我们在学习 Python 编程语言时,经常会用到 Python 的图形界面框架 Tkinter。而 Tkinter 的布局管理器 Layout Manager 有三种,分别是 pack、grid、place。
本篇攻略主要介绍如何在 Tkinter 源码中找到 pack 方法。在 Tkinter 的源码中,pack 方法主要由两个类完成,分别是:CorePack
和 Pack
. 这两个类分别定义了 pack
的基础和具体实现。
首先,我们可以在 Python 安装目录下找到 Tkinter 源码的位置。我们以 Python 3.9.2 版本为例,可以在以下路径找到 tkinter
的源码:
C:\Users\UserName\AppData\Local\Programs\Python\Python399\Lib\tkinter
其中,appdata
和 username
可以根据你的电脑用户名和操作系统版本而变化。接着,我们打开 tkinter
目录下的 __init__.py
文件,可以看到以下代码:
from tkinter import *
import tkinter.ttk as ttk
import tkinter.font as font
# 模块注释...
在 __init__.py
中,我们已经直接导入了 tkinter
模块的全部内容。而 tkinter
模块中的 pack
布局管理器,就是通过 CorePack
和 Pack
两个类完成的。下面,我们详细介绍一下这两个类的作用:
CorePack
CorePack
类是 Pack
类的父类,它定义了 pack
的一些基本属性和方法。它的主要作用如下:
- 定义了一些默认的参数,例如:
fill="none"
,expand="no"
。 - 声明一些实例变量,例如:
self._args
,self._options
。 - 定义了一些实例方法,例如:
_setitem
,_option_dict
,_option_db
,_options
.
下面是 CorePack
类的完整代码示例:
class CorePack:
# 默认参数
_default = {
"anchor": "center",
"expand": "no",
"fill": "none",
"ipadx": 0,
"ipady": 0,
"padx": 0,
"pady": 0,
"side": "top"
}
def _setitem(self, args, kwargs):
"""处理参数"""
if len(args) == 1:
# 传递 option 字典
options = args[0]
else:
# 将 args 转化为 list,方便后面操作
options = list(args)
# 合并 options 和 kwargs 中的参数
for key, value in kwargs.items():
options.append(f"-{key}")
options.append(value)
return options
def _option_dict(self, kwargs):
"""将参数映射成字典"""
options_dict = {}
for key in kwargs:
if key == "side" and kwargs[key]:
options_dict[key] = kwargs[key][0]
else:
options_dict[key] = kwargs[key]
return options_dict
def _option_db(self, kwargs):
"""将参数映射成字典"""
options_dict = {}
for key in kwargs:
if isinstance(kwargs[key], tuple):
options_dict[key] = ",".join(map(str, kwargs[key]))
else:
options_dict[key] = kwargs[key]
return options_dict
def _options(self, args, kwargs):
"""获取选项参数"""
if len(args) == 1 and isinstance(args[0], (int, float, str)):
# 将 args 转化为 list,方便后面操作
args = list(args)
options = []
# args 中的第一个参数为 side
kwargs["side"] = args.pop(0)
options += self._setitem(args, kwargs)
else:
options = self._setitem(args, kwargs)
if "side" not in kwargs:
options.insert(0, "-top")
if not any(x for x in options if x.startswith("-side=")):
options.insert(0, "-side=top")
return self._option_dict(self._option_db(options))
Pack
Pack
类是 CorePack
类的子类,它是 pack
的具体实现。Pack
类的主要作用如下:
- 声明一些实例变量,例如:
self.master
,self.slaves
。 - 定义了一些实例方法,例如:
forget
,info
,place
,propagate
,slaves
,unpack
。
下面是 Pack
类的完整代码示例:
class Pack(CorePack):
"""pack 布局管理器"""
def __init__(self, master=None, cnf={}, **kw):
super().__init__()
# 父容器
self.master = master
# 子容器
self.slaves = []
# 保存配置信息
self._configure(cnf, kw)
def pack_configure(self, cnf={}, **kw):
"""设置控件属性"""
self._configure(cnf, kw)
def pack_forget(self):
"""隐藏控件"""
for slave in self.slaves:
slave.pack_forget()
def pack_info(self, name=None):
"""返回控件的属性"""
if name:
info_list = []
for slave in self.slaves:
info = slave.pack_info()
if info["name"] == name:
return info
raise TclError(f"no {name} packed in {self}")
elif len(self.slaves) == 1:
return self.slaves[0].pack_info()
else:
info_list = []
for slave in self.slaves:
name = slave.pack_info()["name"]
if name:
info_list.append(name)
return tuple(info_list)
def pack_propagate(self, flag=None):
"""允许或禁止控件自动调整"""
if flag is None:
flag = 1
elif isinstance(flag, str):
flag = {"yes": 1, "no": 0, "1": 1, "0": 0}[flag]
elif flag:
flag = 1
else:
flag = 0
self.master.pack_propagate(flag)
def pack_slaves(self):
"""返回子控件"""
return self.slaves
def pack_unpack(self):
"""取消控件"""
for slave in self.slaves:
slave.pack_unpack()
def pack_configure(self, cnf=None, **kw):
"""设置控件属性"""
if cnf is None:
cnf = {}
self._configure(cnf, kw)
def _configure(self, cnf={}, kw={}):
"""设置控件属性"""
cnf = self._option_db(cnf)
kw = self._option_db(kw)
self.master.tk.call(
("pack", "configure", self._name) +
self._options(self._args, cnf, kw))
def _options(self, args, cnf, kw):
"""获取选项参数"""
options = super()._options(args, kw)
if cnf or args:
options += ("-",)
return options + super()._options(args, cnf)
上述代码中,我们可以看到 Pack
类中的 pack_configure
、 pack_forget
、pack_info
、pack_propagate
、pack_slaves
和 pack_unpack
这几个方法,这些方法就是 pack
的具体实现。
同时,Pack
类中还包含 _configure
和 _options
这两个私有方法,它们分别用于配置控件的属性和获取选项参数。需要注意的是,_configure
和 _options
方法定义在 CorePack
类中,因此 Pack
类中只需要继承即可。
通过上述代码和解释,我们已经知道如何在 Tkinter 源码中找到 pack
方法,并且了解了 CorePack
和 Pack
两个类的作用。接下来,我们举两个例子,更具体地说明如何使用 pack
的方法。
例子 1:使用 pack
布局管理器进行水平排列
import tkinter as tk
root = tk.Tk()
for i in range(3):
tk.Button(root, text=f"Button {i}").pack(side="left")
root.mainloop()
这个例子中,我们使用了 pack
的 side
参数实现水平排列。在 for
循环中创建三个按钮,并将它们都设置为 side="left"
,即使它们水平排列。
例子 2:使用 pack
布局管理器进行竖直排列
import tkinter as tk
root = tk.Tk()
for i in range(3):
tk.Button(root, text=f"Button {i}").pack(side="top")
root.mainloop()
这个例子中,我们同样使用了 pack
的 side
参数实现竖直排列。在 for
循环中创建三个按钮,并将它们都设置为 side="top"
,即使它们竖直排列。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Python 图形界面框架TkInter之在源码中找pack方法 - Python技术站