第6篇:PyQt5布局管理器进阶:网格布局与表单布局(完整代码)

哈喽~ 欢迎来到PyQt5系列的第6篇!上一章我们通过“简易文本编辑器”实战,巩固了线性布局(QVBoxLayout/QHBoxLayout)的用法。但在实际开发中,很多复杂界面(比如计算器、用户信息表单、数据展示表格)无法只用线性布局满足——要么控件排列混乱,要么自适应效果差。今天我们就来学习两种进阶布局管理器:网格布局(QGridLayout)和表单布局(QFormLayout),彻底解决复杂界面的排版难题!
一、先明确:进阶布局的核心作用
在学习具体布局前,先搞清楚两种布局的适用场景,避免用错地方:
- 网格布局(QGridLayout):控件按“行×列”的网格排列,适合需要精准控制控件位置的场景(如计算器按钮、表格数据展示);支持控件跨多行/多列,灵活性极高;
- 表单布局(QFormLayout):专门用于“标签+输入框”的表单场景(如用户注册/登录表单、信息填写窗口),自动对齐标签和输入框,界面规整且开发高效。
核心优势:两种布局都支持自适应——窗口缩放时,控件会按预设规则自动调整大小和位置,无需手动计算坐标。
二、网格布局(QGridLayout)详解:从基础到实战
网格布局的核心逻辑是“划分网格、给控件分配行和列”,比如将界面划分为3行3列,每个控件占1个“格子”,也可以让控件占2行1列(跨行吗)、1行2列(跨列)。
1. 网格布局基础用法(完整代码)
先实现一个简单的3×3网格,放置9个按钮,演示基础的行、列分配:
import sys
from PyQt5.QtWidgets import (
QApplication, QWidget, QPushButton, QGridLayout, QLabel
)
from PyQt5.QtCore import Qt
class GridLayoutDemo(QWidget):
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
self.setWindowTitle("QGridLayout网格布局基础演示")
self.resize(400, 300)
# 1. 创建网格布局实例
grid_layout = QGridLayout()
# 设置控件间距(格子之间的距离)
grid_layout.setSpacing(10)
# 设置边距(布局与窗口边缘的距离)
grid_layout.setContentsMargins(20, 20, 20, 20)
# 2. 创建控件并添加到网格布局
# 核心方法:addWidget(控件, 行号, 列号, 占用行数, 占用列数)
# 行号、列号从0开始;占用行数/列数默认是1(可不写)
for i in range(3): # 行:0、1、2
for j in range(3): # 列:0、1、2
btn = QPushButton(f"按钮({i},{j})")
# 添加到网格的(i,j)位置,占1行1列
grid_layout.addWidget(btn, i, j)
# 3. 额外添加一个跨列控件(占1行2列)
cross_col_btn = QPushButton("跨2列按钮")
grid_layout.addWidget(cross_col_btn, 3, 0, 1, 2) # 第4行(索引3),第0列,占1行2列
# 4. 额外添加一个跨行控件(占2行1列)
cross_row_btn = QPushButton("跨2行按钮")
grid_layout.addWidget(cross_row_btn, 0, 3, 2, 1) # 第0行,第4列(索引3),占2行1列
# 5. 将布局绑定到窗口
self.setLayout(grid_layout)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = GridLayoutDemo()
window.show()
sys.exit(app.exec_())
2. 网格布局关键方法解析
网格布局的核心是addWidget()方法,参数含义必须记牢:
addWidget(控件, row, column, rowSpan, columnSpan)
# row:控件所在的行号(从0开始)
# column:控件所在的列号(从0开始)
# rowSpan:控件占用的行数(默认1,即不跨行)
# columnSpan:控件占用的列数(默认1,即不跨列)其他常用方法:
setSpacing(像素值):设置相邻控件之间的间距,避免控件挤在一起;setContentsMargins(左, 上, 右, 下):设置布局与窗口边缘的距离,提升界面美观度;setRowStretch(行号, 拉伸系数):设置某一行的拉伸权重(窗口缩放时,拉伸系数大的行占更多空间);setColumnStretch(列号, 拉伸系数):设置某一列的拉伸权重,同理。
3. 网格布局实战:简易计算器界面(核心场景)
计算器是网格布局的典型应用——按钮按固定网格排列,部分按钮(如“0”“=”)跨列。我们实现一个简易计算器的界面(含输入框+按钮区):
import sys
from PyQt5.QtWidgets import (
QApplication, QWidget, QPushButton, QGridLayout, QLineEdit
)
from PyQt5.QtCore import Qt
class SimpleCalculator(QWidget):
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
self.setWindowTitle("简易计算器(网格布局实战)")
self.resize(350, 400)
# 1. 创建主布局(垂直布局:输入框在上,按钮区在下)
main_layout = QGridLayout()
main_layout.setSpacing(10)
main_layout.setContentsMargins(15, 15, 15, 15)
# 2. 创建输入框(占1行4列)
self.input_edit = QLineEdit()
self.input_edit.setAlignment(Qt.AlignRight) # 文本右对齐(符合计算器习惯)
self.input_edit.setStyleSheet("font-size: 20px; padding: 10px;")
self.input_edit.setReadOnly(True) # 输入框只读,通过按钮输入
main_layout.addWidget(self.input_edit, 0, 0, 1, 4) # 第0行,第0列,占1行4列
# 3. 定义计算器按钮文本(按网格顺序排列)
btn_texts = [
'7', '8', '9', '/',
'4', '5', '6', '*',
'1', '2', '3', '-',
'0', '.', '=', '+',
'C' # 清空按钮
]
# 4. 给按钮分配行和列,添加到网格布局
row = 1 # 从第1行开始(第0行是输入框)
col = 0
for text in btn_texts:
btn = QPushButton(text)
btn.setStyleSheet("font-size: 16px; padding: 15px;")
# 特殊处理:0按钮跨2列,C按钮跨2列
if text == '0':
main_layout.addWidget(btn, row, col, 1, 2) # 占1行2列
col += 2 # 列号+2(跳过一个格子)
elif text == 'C':
main_layout.addWidget(btn, row, col, 1, 2) # 占1行2列
col += 2
else:
main_layout.addWidget(btn, row, col) # 默认占1行1列
col += 1
# 每4列换行(计算器是4列按钮)
if col >= 4:
col = 0
row += 1
# 5. 绑定布局到窗口
self.setLayout(main_layout)
# 6. 绑定按钮点击信号(简单演示:点击按钮显示文本到输入框)
for i in range(main_layout.count()):
widget = main_layout.itemAt(i).widget()
if isinstance(widget, QPushButton):
widget.clicked.connect(self.on_btn_click)
def on_btn_click(self):
"""按钮点击槽函数:将按钮文本显示到输入框"""
sender = self.sender()
text = sender.text()
if text == 'C':
# 清空输入框
self.input_edit.clear()
elif text == '=':
# 简单计算(实际项目需处理异常,此处简化)
try:
result = eval(self.input_edit.text())
self.input_edit.setText(str(result))
except:
self.input_edit.setText("错误")
else:
# 拼接文本
current_text = self.input_edit.text()
self.input_edit.setText(current_text + text)
if __name__ == "__main__":
app = QApplication(sys.argv)
calculator = SimpleCalculator()
calculator.show()
sys.exit(app.exec_())4. 计算器界面亮点
- 用网格布局精准还原计算器的按钮排列,“0”和“C”按钮跨列,符合实际计算器的交互习惯;
- 结合垂直布局的思路,将输入框和按钮区整合,界面层次清晰;
- 实现了基础的计算逻辑(数字拼接、清空、结果计算),信号与槽绑定简洁高效。
三、表单布局(QFormLayout)详解:高效实现表单界面
表单布局是“标签+输入框”的专用布局,无需手动调整对齐方式——它会自动将标签放在左侧、输入控件放在右侧,且所有标签和输入框分别对齐,开发效率极高。
1. 表单布局基础用法(完整代码)
实现一个简单的用户注册表单,包含“用户名、密码、邮箱、电话”四个字段:
import sys
from PyQt5.QtWidgets import (
QApplication, QWidget, QLabel, QLineEdit,
QPushButton, QFormLayout, QVBoxLayout, QComboBox
)
from PyQt5.QtCore import Qt
class FormLayoutDemo(QWidget):
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
self.setWindowTitle("QFormLayout表单布局基础演示")
self.resize(400, 300)
# 1. 创建主布局(垂直布局:表单在上,按钮在下)
main_layout = QVBoxLayout()
main_layout.setSpacing(20)
main_layout.setContentsMargins(30, 30, 30, 30)
# 2. 创建表单布局实例
form_layout = QFormLayout()
form_layout.setSpacing(15) # 标签与输入框、行与行之间的间距
# 3. 创建标签和输入控件,添加到表单布局
# 核心方法:addRow(标签文本/标签控件, 输入控件)
# 方式1:直接传标签文本(自动生成QLabel)
form_layout.addRow("用户名:", QLineEdit())
# 方式2:传QLabel控件(可自定义标签样式)
pwd_label = QLabel("密码:")
pwd_label.setStyleSheet("color: #e74c3c;")
pwd_edit = QLineEdit()
pwd_edit.setEchoMode(QLineEdit.Password) # 密码隐藏
form_layout.addRow(pwd_label, pwd_edit)
# 方式3:输入控件可以是其他类型(如下拉框)
form_layout.addRow("性别:", QComboBox())
# 方式4:添加提示标签(跨两列)
tip_label = QLabel("* 带星号的为必填项")
tip_label.setStyleSheet("color: #95a5a6; font-size: 12px;")
form_layout.addRow(tip_label) # 无输入控件时,标签跨两列
# 4. 调整标签对齐方式(默认左对齐,可改为右对齐)
form_layout.setLabelAlignment(Qt.AlignRight)
# 5. 创建提交按钮
submit_btn = QPushButton("提交表单")
submit_btn.setStyleSheet("background-color: #3498db; color: white; padding: 8px;")
# 6. 将表单布局和按钮添加到主布局
main_layout.addLayout(form_layout)
main_layout.addWidget(submit_btn, alignment=Qt.AlignCenter)
# 7. 绑定布局到窗口
self.setLayout(main_layout)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = FormLayoutDemo()
window.show()
sys.exit(app.exec_())2. 表单布局关键方法解析
addRow(标签, 输入控件):核心方法,添加一行表单;标签可以是字符串(自动生成QLabel)或QLabel实例,输入控件可以是QLineEdit、QComboBox等任意交互控件;setLabelAlignment(对齐方式):设置标签的对齐方式(如Qt.AlignRight让标签右对齐,与输入框间距更紧凑);setSpacing(像素值):设置“标签与输入框之间”和“相邻行之间”的间距;setFieldGrowthPolicy(策略):设置输入控件的拉伸策略(如QFormLayout.ExpandingFieldsGrow让输入控件随窗口缩放而拉伸)。
3. 表单布局实战:完整用户信息登记表单
整合表单布局和之前学的控件,实现一个完整的用户信息登记表单,包含输入框、下拉框、复选框,添加表单验证逻辑:
import sys
from PyQt5.QtWidgets import (
QApplication, QWidget, QLabel, QLineEdit,
QPushButton, QFormLayout, QVBoxLayout, QComboBox,
QCheckBox, QMessageBox
)
from PyQt5.QtCore import Qt
class UserInfoForm(QWidget):
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
self.setWindowTitle("用户信息登记表单(表单布局实战)")
self.resize(450, 350)
self.setStyleSheet("font-size: 14px; color: #2c3e50;")
# 1. 主布局
main_layout = QVBoxLayout()
main_layout.setSpacing(20)
main_layout.setContentsMargins(30, 30, 30, 30)
# 2. 表单布局
form_layout = QFormLayout()
form_layout.setSpacing(15)
form_layout.setLabelAlignment(Qt.AlignRight)
# 设置输入控件拉伸(随窗口缩放)
form_layout.setFieldGrowthPolicy(QFormLayout.ExpandingFieldsGrow)
# 3. 表单控件初始化
self.user_edit = QLineEdit()
self.user_edit.setPlaceholderText("请输入用户名(3-10个字符)")
self.pwd_edit = QLineEdit()
self.pwd_edit.setEchoMode(QLineEdit.Password)
self.pwd_edit.setPlaceholderText("请输入密码(6-16个字符)")
self.email_edit = QLineEdit()
self.email_edit.setPlaceholderText("请输入邮箱(如xxx@xxx.com)")
self.gender_combo = QComboBox()
self.gender_combo.addItems(["男", "女", "保密"])
self.phone_edit = QLineEdit()
self.phone_edit.setPlaceholderText("请输入手机号(11位数字)")
# 4. 添加表单行
form_layout.addRow("用户名*:", self.user_edit)
form_layout.addRow("密码*:", self.pwd_edit)
form_layout.addRow("邮箱*:", self.email_edit)
form_layout.addRow("性别:", self.gender_combo)
form_layout.addRow("手机号:", self.phone_edit)
# 同意条款复选框(跨两列)
self.agree_check = QCheckBox("我已阅读并同意《用户服务条款》")
form_layout.addRow(self.agree_check)
# 5. 提交按钮
self.submit_btn = QPushButton("提交信息")
self.submit_btn.setStyleSheet("""
QPushButton {
background-color: #27ae60;
color: white;
padding: 10px;
border: none;
border-radius: 4px;
}
QPushButton:hover {
background-color: #219653;
}
""")
# 6. 结果显示标签
self.result_label = QLabel("")
self.result_label.setAlignment(Qt.AlignCenter)
# 7. 添加到主布局
main_layout.addLayout(form_layout)
main_layout.addWidget(self.submit_btn, alignment=Qt.AlignCenter)
main_layout.addWidget(self.result_label)
# 8. 绑定布局和信号
self.setLayout(main_layout)
self.submit_btn.clicked.connect(self.check_form)
def check_form(self):
"""表单验证逻辑:检查必填项、格式正确性"""
# 1. 获取表单内容
username = self.user_edit.text().strip()
password = self.pwd_edit.text().strip()
email = self.email_edit.text().strip()
gender = self.gender_combo.currentText()
phone = self.phone_edit.text().strip()
# 2. 验证必填项
if not username:
QMessageBox.warning(self, "验证失败", "用户名不能为空!")
return
if not password:
QMessageBox.warning(self, "验证失败", "密码不能为空!")
return
if not email:
QMessageBox.warning(self, "验证失败", "邮箱不能为空!")
return
if not self.agree_check.isChecked():
QMessageBox.warning(self, "验证失败", "请同意用户服务条款!")
return
# 3. 验证格式(简化版)
if len(username) < 3 or len(username) > 10:
QMessageBox.warning(self, "验证失败", "用户名长度需在3-10个字符之间!")
return
if len(password) < 6 or len(password) > 16:
QMessageBox.warning(self, "验证失败", "密码长度需在6-16个字符之间!")
return
if "@" not in email:
QMessageBox.warning(self, "验证失败", "邮箱格式不正确(需包含@)!")
return
if phone and len(phone) != 11:
QMessageBox.warning(self, "验证失败", "手机号需为11位数字!")
return
# 4. 验证通过,显示结果
result = f"""
信息提交成功!
用户名:{username}
性别:{gender}
邮箱:{email}
手机号:{phone if phone else "未填写"}
"""
self.result_label.setText(result)
self.result_label.setStyleSheet("color: #27ae60;")
if __name__ == "__main__":
app = QApplication(sys.argv)
form = UserInfoForm()
form.show()
sys.exit(app.exec_())5. 实战表单亮点
- 用表单布局快速实现规整的表单界面,标签右对齐,输入框自适应拉伸,开发效率高;
- 添加了完整的表单验证逻辑(必填项检查、格式验证),用
QMessageBox弹出提示,提升用户体验; - 结合了多种控件(输入框、下拉框、复选框),覆盖实际表单的常见场景;
- 美化了按钮样式(悬停效果、圆角),界面更美观。
四、布局嵌套技巧:复杂界面的核心思路
实际开发中,很少用单一布局完成复杂界面,而是通过“布局嵌套”组合使用——比如“主布局(垂直)”包含“表单布局”和“网格布局”,再搭配“水平布局”排列按钮。
嵌套核心原则:
- 先划分界面大区域(如“顶部标题区、中间内容区、底部按钮区”),用主布局(垂直/水平)管理;
- 每个小区域内部,根据控件类型选择合适的子布局(网格/表单/线性);
- 用
addLayout()方法将子布局添加到主布局,实现层次化管理。
五、常见问题排查
- 问题1:网格布局控件重叠/位置错乱 → 解决:检查行号、列号是否正确,避免多个控件分配到同一个格子;跨行列时注意
rowSpan和columnSpan的数值; - 问题2:表单布局标签和输入框不对齐 → 解决:用
setLabelAlignment()统一标签对齐方式;避免手动设置输入控件的固定宽度(让布局自动适配); - 问题3:窗口缩放时控件不拉伸 → 解决:给布局添加拉伸系数(
setRowStretch/setColumnStretch),或设置输入控件的拉伸策略(如表单布局的setFieldGrowthPolicy); - 问题4:布局嵌套后界面混乱 → 解决:先画界面草图,明确大区域和子区域的划分;给每个布局添加
setSpacing和setContentsMargins,避免间距混乱。
总结
本章我们掌握了两种进阶布局管理器的核心用法:
- 网格布局(QGridLayout):适合“行×列”的规整排列场景(如计算器),支持控件跨行列,灵活性极高;
- 表单布局(QFormLayout):专门用于“标签+输入框”的表单场景,自动对齐,开发效率高;
- 布局嵌套是复杂界面的核心思路,先划分大区域,再用子布局管理小区域。
下一章我们将学习PyQt5的文本与表格控件(QTextEdit与QTableWidget),进一步拓展界面的功能边界。如果在布局实操中遇到问题,或者有复杂界面的排版需求,欢迎在评论区留言讨论~