🐸 青蛙编程网
首页 / Python / 桌面客户端 / 4. 布局管理:pack / grid / place

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 钉坐标;一容器一管家,混用必卡死。

动手改

  1. 给上面计算器骨架把"0"改成横跨两列(提示:判断 txt == "0" 时 grid 参数换 columnspan=2)
  2. 只用 pack() 重做一个"左输入框、右按钮"的横排界面(提示:输入框 side="left", expand=True, fill="x",按钮 side="right")
  3. 试着故意把一个控件的 grid 改成 pack,亲历一次"卡死",再改回来——这个坑必须踩过一次才记得住

下一章:事件与变量:让界面动起来 🐸

📥 下载本章代码

ZIP 内含本章全部代码文件与说明,解压即用,与教程内容同步生成。