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 选项卡容器,分页 核心特性 • addWidget(控件, 行, 列, 行跨度, 列跨度) • setColumnStretch / setRowStretch • 支持跨行跨列 核心特性 • addRow(标签, 控件) • 自动对齐标签 • 支持行换行模式 核心特性 • 带标题的边框 • setCheckable(True) 可勾选 • 内部控件统一禁用/启用 核心特性 • addTab(控件, 标题) • setTabsClosable 可关闭 • 标签位置可调 组合使用,构建专业级界面

这张图里,四个组件各司其职。QGridLayout负责精确控制位置,QFormLayout专攻表单场景,QGroupBox做视觉分组,QTabWidget做功能分页。实际项目中,它们经常组合使用——比如在QTabWidget的某个标签页里,放一个QGroupBox,里面再用QFormLayout排列控件。

好了,这一章的内容就到这里。记住一句话:布局是界面的骨架,容器是界面的房间。骨架搭好了,房间分清楚了,你的界面就成功了一大半。

课后练习建议:试着用本章学到的知识,做一个「用户设置」界面。包含三个标签页:基本设置(用QFormLayout)、高级设置(用QGridLayout)、关于(用QGroupBox)。做完之后,你会发现自己对布局的理解又上了一个台阶。

可可精品资料库