Pack 为一布局管理器,可将它视为一个弹性的容器
一个空的 widget
代码:
import tkinter as tk
root = tk.Tk()
# 查看当前 root 下的子组件,解释器没有报异常,说明 Pack 已创建,
# 并可以使用,此时的输出为空,即 root 没有任何子组件
print(root.pack_slaves())
# 向 root 中 pack 一个 Label
tk.Label(root,text='pack').pack()
# 再次打印出 root 的子组件,可以看到已经包含一个组件,
# 即刚才创建的 Label,说明 Label调用 pack()是将自己加入到了 root 中
print(root.pack_slaves())
root.mainloop()
结果:
pack_salves 打印当前组件包拥有的子组件,通过这个函数可以查看各个组件是否有包含关系
root 与 Pack 的关系
使用文字 create_text
代码:
import tkinter as tk
root = tk.Tk()
# 改变 root 的大小为80x80
root.geometry('80x80+0+0')
print(root.pack_slaves()) # 查看组件是否存在
# 向 root 中 pack 一个 Label
tk.Label(root,text='pack').pack()
print(root.pack_slaves()) # 查看组件是否存在
root.mainloop()
结果:
可以看出 Pack 的结果没有什么变化,它不对 root 产生影响,也就是说 Pack 可以“缩小”至只包含一个 Label 组件,root 可以自己控件自己的大小
向 Pack 中添加多个组件
向 Pack 中添加多个 Label
代码:
import tkinter as tk
root = tk.Tk()
# 改变 root 的大小为80x80
root.geometry('80x80+0+0')
print(root.pack_slaves()) # 查看组件是否存在
# 向 root 中 pack 多个 Label
for i in range(5):
tk.Label(root, text='pack'+str(i)).pack()
print(root.pack_slaves()) # 查看组件是否存在
root.mainloop()
结果:
使用用默认的设置 pack 将向下添加组件,第一个在最上方,然后是依次向下排列。注意最后一个 Label 的显示不完全,因为root大小设置了,Label超出范围了
固定设置到自由变化
上例中看到 label4没有显示完全
代码:
import tkinter as tk
root = tk.Tk()
# 向 root 中 pack 多个 Label
for i in range(5):
tk.Label(root, text='pack'+str(i)).pack()
print(root.pack_slaves()) # 查看组件是否存在
root.mainloop()
结果:
使用用默认的设置 pack 将向下添加组件,第一个在最上方,然后是依次向下排列。这样的话最后一个已经显示出来的,这就是为什么称 Pack 为弹性的容器的原因了,虽然有这个特性,但它并不是总是能够按照我们的意思进行布局,我们可以强制设置容器的大小,以覆盖 Pack 的默认设置。Pack 的优先级低。
fill 如何控制子组件的布局
不设置 root 的大小,使用默认
代码:
import tkinter as tk
root = tk.Tk()
# 向 root 中 pack 多个 Label
tk.Label(root, text='pack1',bg='red').pack(fill='y')
tk.Label(root, text='pack2',bg='blue').pack(fill='both')
tk.Label(root, text='pack3',bg='green').pack(fill='x')
print(root.pack_slaves())
root.mainloop()
结果:
expand 如何控制组件的布局
这个属性指定如何使用额外的空间,即上例中留下来的“空白”
代码:
import tkinter as tk
root = tk.Tk()
# 向 root 中 pack 多个 Label
tk.Label(root, text='pack1',bg='red').pack(fill='y',expand=1)
tk.Label(root, text='pack2',bg='blue').pack(fill='both',expand=1)
tk.Label(root, text='pack3',bg='green').pack(fill='x',expand=0)
print(root.pack_slaves())
root.mainloop()
结果:
第一个只保证在 Y 方向填充,第二个保证在 XY 两个方向上填充,第三个不使用填充属性,这个例子中第一个 Label 和第二个 Label 使用了 expand = 1属性,而第三个使用 expand =0属性,改变 root 的大小,可以看到 Label1和 Label2是随着 root 的大小变化而变化(严格地它的可用空间在变化),第三个只中使用 fill 进行 X 方向上的填充,不使用额外的空间
改变组件的排放位置
使用 side 属性改变放置位置
代码:
import tkinter as tk
root = tk.Tk()
# 向 root 中 pack 多个 Label
tk.Label(root, text='pack1',bg='red').pack(fill='y',expand=1,side='left')
tk.Label(root, text='pack2',bg='blue').pack(fill='both',expand=1,side='right')
tk.Label(root, text='pack3',bg='green').pack(fill='x',expand=0,side='left')
print(root.pack_slaves())
root.mainloop()
结果:
设置组件之间的间隙大小
ipadx 设置内部间隙
padx 设置外部间隙
代码:
import tkinter as tk
root = tk.Tk()
# 创建三个 Label 分别使用不同的 fill 属性,改为水平放置
# 将第一个 LabelFrame 居左放置
L1 = tk.LabelFrame(root, text='pack1', bg='red')
# 设置 ipadx 属性为20
L1.pack(side='left', ipadx=20)
tk.Label(L1, text='inside', bg='blue').pack(expand=1, side='left')
L2 = tk.Label(root, text='pack2', bg='blue').pack(fill='both',expand=1,side='left',padx=10)
L3 = tk.Label(root, text='pack3', bg='green').pack(fill='x',expand=0,side='left',pady=10)
root.mainloop()
结果:
为了演示 ipadx/padx,创建了一个 LabelFrame 设置它的 ipadx 为20,即内部间隔值为20,它的子组件若使用则会留出20个单位;Label2和 Label3分别设置 x 和 y 方向上的外部间隔值,所有与之排列的组件会与之保留10个单位值的距离