4. 布局管理:pack / grid / place
这是什么:布局管理器决定控件摆在窗口哪个位置。Tkinter 给三选一:pack() 按上下左右顺序堆、grid() 按行列表格摆、place() 按坐标钉死。
为什么用:上一章所有控件都竖着排成一条——因为 pack() 默认从上往下堆。想做出"输入框占一排、两个按钮并排一排"的正常界面,全靠布局管理;不会它,界面永远是一根面条。
如何用:三种管理器各配一个例子跑一遍,重点掌握日常 80% 场景都在用的 grid()。
pack:从上到下堆面条
import tkinter as tk
root = tk.Tk()
root.title("pack 演示")
tk.Label(root, text="第一行", bg="#ffd7d7").pack(fill="x")
tk.Label(root, text="第二行", bg="#d7ffd7").pack(side="left")
tk.Label(root, text="第三行", bg="#d7d7ff").pack(side="left")
root.mainloop()
你会看到:第一行红底标签横贯整个窗口宽;第二、三行蓝绿两个标签并排在左下。
| 参数 | 作用 |
|---|---|
side="top"(默认) |
从哪条边往里堆:top/bottom/left/right |
fill="x" / "both" |
沿某个方向撑满(配合 side 用) |
padx / pady |
控件四周留白 |
expand=True |
窗口变大时跟着吃剩余空间 |
grid:行列表格,主力选手
import tkinter as tk
root = tk.Tk()
root.title("grid 计算器骨架")
root.geometry("240x200")
digits = [["7", "8", "9"], ["4", "5", "6"], ["1", "2", "3"], ["0", "+", "="]]
for r, row in enumerate(digits):
for c, txt in enumerate(row):
tk.Button(root, text=txt).grid(row=r, column=c,
sticky="nsew", padx=2, pady=2)
for i in range(3):
root.grid_columnconfigure(i, weight=1)
for i in range(4):
root.grid_rowconfigure(i, weight=1)
root.mainloop()
你会看到:一个 4 行 3 列的计算器按钮矩阵,拖大窗口按钮跟着均匀变大。
| 参数 | 作用 |
|---|---|
row=r, column=c |
表格坐标,从 0 数 |
sticky="nsew" |
控件"贴住"上下左右边(北南东西四个字母),撑满所在格子 |
columnspan=2 |
横向占两列(放"0"按钮这种宽键用) |
grid_columnconfigure(i, weight=1) |
声明第 i 列在窗口变大时按比例分多余空间——不加这行,按钮挤在左上角不动 |
双层循环按行列摆控件是 GUI 代码的日常,务必看懂上面那 4 行循环。
place:坐标钉死,慎用
btn = tk.Button(root, text="钉在这")
btn.place(x=50, y=80) # 距容器左上角 (50, 80) 像素
btn.place(relx=0.5, rely=0.5,
anchor="center") # 或按容器百分比定位,anchor 是锚点
窗口一缩放 x/y 就错位,所以 place 只用于悬浮提示、覆盖层这种特殊场合,正常界面别拿它当家。
头号大坑:同一容器里混用 pack 和 grid
同一个父容器(比如 root)里的兄弟控件,一部分调 pack()、另一部分调 grid()——程序直接卡死:窗口灰掉、无限转圈、不报错也不退出。原因:两者都想接管容器尺寸计算,互相等对方先让步,就成了死锁。
规矩记死:一个容器只用一种布局管理器。 真要混排,用 tk.Frame(空白容器)分区:外层 grid,每个 Frame 内部随便用哪种。
记忆口诀:pack 堆面条,grid 摆表格,place 钉坐标;一容器一管家,混用必卡死。
动手改
- 给上面计算器骨架把"0"改成横跨两列(提示:判断
txt == "0"时 grid 参数换columnspan=2) - 只用
pack()重做一个"左输入框、右按钮"的横排界面(提示:输入框side="left", expand=True, fill="x",按钮side="right") - 试着故意把一个控件的
grid改成pack,亲历一次"卡死",再改回来——这个坑必须踩过一次才记得住
下一章:事件与变量:让界面动起来 🐸