4、高级布局与容器:QGridLayout网格布局、QFormLayout表单布局、QGroupBox与QTabWidget容器
各位同学,今天我们来聊聊Qt里真正能撑起界面的几个家伙。
前面我们学了QHBoxLayout和QVBoxLayout,说白了就是横着排、竖着排。但实际项目里,哪有这么简单?你想想看,一个设置界面,左边是标签,右边是输入框,下面还有一排按钮——这种场景,光靠水平垂直堆叠,你得嵌套多少层布局?
我个人习惯,遇到这种需求,直接上网格布局。省心,也省代码。
4.1 QGridLayout:网格布局,让控件各就各位
QGridLayout,顾名思义,就是把界面划分成网格。每个控件占据一个格子,或者跨行跨列。
我在项目中遇到过最典型的场景:做一个计算器界面。数字按钮、运算符、等号、清空——每个按钮大小不一样,位置也不一样。用QGridLayout,几行代码就搞定了。
核心概念:
- 行和列从0开始编号
- 控件可以跨多行或多列
- 行高和列宽可以自适应,也可以固定
来看一个实际例子:
# 创建一个网格布局
grid = QGridLayout()
# 添加控件到指定位置
# addWidget(控件, 行, 列, 行跨度, 列跨度)
grid.addWidget(label_name, 0, 0) # 第0行第0列
grid.addWidget(edit_name, 0, 1) # 第0行第1列
grid.addWidget(label_age, 1, 0) # 第1行第0列
grid.addWidget(edit_age, 1, 1) # 第1行第1列
grid.addWidget(btn_submit, 2, 0, 1, 2) # 第2行,跨2列
# 设置列宽比例
grid.setColumnStretch(0, 1) # 第0列占1份
grid.setColumnStretch(1, 3) # 第1列占3份
嗯,这里要注意:行跨度和列跨度这两个参数,很多人容易搞混。我刚开始学的时候也栽过跟头——明明想让按钮占满整行,结果只占了半个格子。后来才明白,跨度是从当前位置开始,往后占几个格子。
我的小技巧:调试布局时,可以临时给每个控件设置不同的背景色。这样一眼就能看出每个控件占了多少空间,哪里不对马上就能发现。
4.2 QFormLayout:表单布局,专为标签+输入框而生
QFormLayout,说白了就是「标签-字段」对。你想想看,登录界面、注册界面、设置界面——几乎全是这种模式:左边一个标签,右边一个输入框。
用QGridLayout当然也能实现,但QFormLayout更省事。它自动帮你对齐标签,自动处理换行,甚至还能自动调整标签的宽度。
# 创建表单布局
form = QFormLayout()
# 添加行:addRow(标签文本, 输入控件)
form.addRow("用户名:", QLineEdit())
form.addRow("密码:", QLineEdit())
form.addRow("邮箱:", QLineEdit())
# 也可以添加自定义标签控件
label = QLabel("备注:")
edit = QTextEdit()
form.addRow(label, edit)
# 添加按钮行
form.addRow(QPushButton("提交"))
我曾经在一个项目中,用QFormLayout做了个几十个字段的配置界面。一开始担心性能,后来发现完全没问题。而且它支持行换行模式——当窗口变窄时,标签和输入框会自动上下排列,而不是挤在一起。
注意:QFormLayout默认的标签对齐方式是右对齐。如果你想要左对齐,需要手动设置:form.setLabelAlignment(Qt.AlignLeft)。我当年就因为没注意这个,被UI设计师追着改了三版……
4.3 QGroupBox:分组框,把相关控件装进一个盒子
QGroupBox,就是一个带标题的框。它可以把一组相关的控件「圈」在一起,视觉上更清晰。
你想想看,一个设置界面,有「基本设置」「高级设置」「网络设置」——每个区域用QGroupBox包起来,用户一眼就能看出哪些控件是相关的。
# 创建一个分组框
group_basic = QGroupBox("基本设置")
# 在分组框内部创建布局
layout = QVBoxLayout()
layout.addWidget(QLabel("用户名:"))
layout.addWidget(QLineEdit())
layout.addWidget(QLabel("密码:"))
layout.addWidget(QLineEdit())
group_basic.setLayout(layout)
# 把分组框添加到主布局
main_layout.addWidget(group_basic)
QGroupBox还有一个很实用的功能:可勾选。设置setCheckable(True)后,分组框前面会出现一个复选框。勾选时,内部所有控件才可用;取消勾选,内部控件全部禁用。
应用场景:我在做一个数据采集软件时,把「高级过滤条件」放在一个可勾选的QGroupBox里。默认不勾选,用户需要时才打开。这样界面简洁,功能又不缺失。
4.4 QTabWidget:选项卡容器,一页放不下?分页!
QTabWidget,就是带标签页的容器。每个标签页可以放一个独立的控件或布局。
说实话,这是我最常用的容器之一。一个复杂的配置界面,如果所有控件都堆在一个页面里,用户看着就头疼。用QTabWidget分成几个标签页,每个标签页只放一类功能,用户体验瞬间提升。
# 创建选项卡控件
tabs = QTabWidget()
# 创建各个标签页
tab1 = QWidget()
tab2 = QWidget()
tab3 = QWidget()
# 为每个标签页设置布局
layout1 = QVBoxLayout()
layout1.addWidget(QLabel("这是基本设置"))
tab1.setLayout(layout1)
layout2 = QVBoxLayout()
layout2.addWidget(QLabel("这是高级设置"))
tab2.setLayout(layout2)
layout3 = QVBoxLayout()
layout3.addWidget(QLabel("这是关于信息"))
tab3.setLayout(layout3)
# 添加标签页
tabs.addTab(tab1, "基本")
tabs.addTab(tab2, "高级")
tabs.addTab(tab3, "关于")
# 设置当前显示的标签页
tabs.setCurrentIndex(0)
QTabWidget还有一些很实用的特性:
- 可关闭标签页:设置
setTabsClosable(True),用户点击X就能关闭 - 标签位置:可以放在顶部、底部、左侧、右侧
- 图标支持:每个标签页可以带图标
避坑指南:我曾经在QTabWidget里嵌套了另一个QTabWidget,结果界面变得非常奇怪。后来发现,尽量避免多层嵌套,否则用户会迷失在标签页的海洋里。一层就够了,最多两层。
4.5 知识体系总览
下面这张图,是我自己总结的本章知识体系。你可以把它当作一个「地图」,学完之后对照着检查自己掌握了多少。
这张图里,四个组件各司其职。QGridLayout负责精确控制位置,QFormLayout专攻表单场景,QGroupBox做视觉分组,QTabWidget做功能分页。实际项目中,它们经常组合使用——比如在QTabWidget的某个标签页里,放一个QGroupBox,里面再用QFormLayout排列控件。
好了,这一章的内容就到这里。记住一句话:布局是界面的骨架,容器是界面的房间。骨架搭好了,房间分清楚了,你的界面就成功了一大半。
课后练习建议:试着用本章学到的知识,做一个「用户设置」界面。包含三个标签页:基本设置(用QFormLayout)、高级设置(用QGridLayout)、关于(用QGroupBox)。做完之后,你会发现自己对布局的理解又上了一个台阶。
可可精品资料库