第9篇:PyQt5容器控件:QTabWidget与QGroupBox(完整代码)
哈喽~ 欢迎来到PyQt5系列的第9篇!上一章我们掌握了QDialog和各类标准对话框,解决了界面的交互弹窗问题。今天我们聚焦容器控件——这类控件的核心作用是“管理其他控件”,把功能相关的控件分组/分页面摆放,让复杂界面更规整、层次感更强。我们会详细讲解两种高频容器控件:QGroupBox(分组框)和QTabWidget(标签页控件),全程搭配完整可运行代码,新手也能轻松掌握!
一、先明确:容器控件的核心定位
容器控件本身不实现业务功能,而是作为“控件的容器”存在,核心价值是提升界面的结构化和可读性:
- QGroupBox(分组框):把功能相关的控件(如设置项、表单字段)“分组”展示,带标题和可选边框,用户能快速识别控件的功能归属;
- QTabWidget(标签页控件):把不同功能模块(如文本编辑、数据表格、系统设置)“分页面”展示,通过点击标签切换页面,极大节省界面空间,适合多功能集成的窗口。
二、QGroupBox(分组框)详解:控件分组管理
QGroupBox是最基础的容器控件,核心是“给控件加分组标题+边框”,支持“可勾选分组”(勾选后才启用内部控件),是规整表单/设置界面的必备工具。
1. QGroupBox基础用法(完整代码)
实现两个分组框(“界面设置”和“数据设置”),演示分组框的基础属性和可勾选功能:
import sys
from PyQt5.QtWidgets import (
QApplication, QWidget, QVBoxLayout, QHBoxLayout,
QGroupBox, QLabel, QCheckBox, QComboBox, QPushButton
)
from PyQt5.QtCore import Qt
class GroupBoxDemo(QWidget):
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
self.setWindowTitle("QGroupBox分组框基础演示")
self.resize(500, 400)
# 主布局(垂直):两个分组框 + 确认按钮
main_layout = QVBoxLayout()
main_layout.setSpacing(20)
main_layout.setContentsMargins(30, 30, 30, 30)
# ---------- 分组框1:界面设置(普通分组,不可勾选) ----------
ui_group = QGroupBox("界面设置") # 设置分组标题
ui_group.setAlignment(Qt.AlignCenter) # 标题居中对齐
# 分组框内部布局(网格布局)
ui_layout = QHBoxLayout()
ui_layout.setSpacing(15)
# 添加内部控件
theme_label = QLabel("主题:")
theme_combo = QComboBox()
theme_combo.addItems(["浅色主题", "深色主题", "系统主题"])
font_size_label = QLabel("字体大小:")
font_size_combo = QComboBox()
font_size_combo.addItems(["12px", "14px", "16px"])
# 添加到分组框布局
ui_layout.addWidget(theme_label)
ui_layout.addWidget(theme_combo)
ui_layout.addWidget(font_size_label)
ui_layout.addWidget(font_size_combo)
# 绑定布局到分组框
ui_group.setLayout(ui_layout)
# ---------- 分组框2:数据设置(可勾选分组,勾选才启用内部控件) ----------
data_group = QGroupBox("数据设置")
data_group.setCheckable(True) # 开启勾选功能
data_group.setChecked(False) # 默认未勾选(内部控件禁用)
# 分组框内部布局(水平)
data_layout = QHBoxLayout()
data_layout.setSpacing(15)
# 添加内部控件
auto_save_check = QCheckBox("自动保存")
auto_sync_check = QCheckBox("自动同步")
# 添加到分组框布局
data_layout.addWidget(auto_save_check)
data_layout.addWidget(auto_sync_check)
# 绑定布局到分组框
data_group.setLayout(data_layout)
# 确认按钮
confirm_btn = QPushButton("保存设置")
confirm_btn.setFixedSize(100, 30)
# 将分组框和按钮添加到主布局
main_layout.addWidget(ui_group)
main_layout.addWidget(data_group)
main_layout.addWidget(confirm_btn, alignment=Qt.AlignCenter)
# 绑定主布局到窗口
self.setLayout(main_layout)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = GroupBoxDemo()
window.show()
sys.exit(app.exec_())2. QGroupBox核心方法解析
QGroupBox的核心围绕“分组样式”和“交互控制”,重点掌握:
| 方法 | 作用 |
|---|---|
setTitle(标题文本) | 设置分组框的标题 |
setAlignment(对齐方式) | 设置标题对齐(如Qt.AlignCenter居中、Qt.AlignLeft左对齐) |
setCheckable(True/False) | 是否开启“勾选功能”(勾选后内部控件启用,未勾选禁用) |
setChecked(True/False) | 设置勾选状态(仅当setCheckable(True)时生效) |
setStyleSheet(样式) | 自定义分组框样式(如边框颜色、标题字体) |
3. QGroupBox实战:表单字段分组
结合之前学的表单布局,用QGroupBox将用户表单分为“基础信息”和“扩展信息”两组,提升表单可读性:
import sys
from PyQt5.QtWidgets import (
QApplication, QWidget, QVBoxLayout, QFormLayout,
QGroupBox, QLineEdit, QComboBox, QTextEdit, QPushButton
)
from PyQt5.QtCore import Qt
class GroupBoxFormDemo(QWidget):
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
self.setWindowTitle("QGroupBox表单分组实战")
self.resize(500, 450)
# 主布局
main_layout = QVBoxLayout()
main_layout.setSpacing(20)
main_layout.setContentsMargins(30, 30, 30, 30)
# ---------- 分组1:基础信息 ----------
basic_group = QGroupBox("基础信息(必填)")
basic_layout = QFormLayout()
basic_layout.setSpacing(15)
# 添加表单控件
basic_layout.addRow("用户名:", QLineEdit())
basic_layout.addRow("密码:", QLineEdit())
basic_layout.addRow("性别:", QComboBox())
basic_layout.addRow("手机号:", QLineEdit())
# 绑定布局
basic_group.setLayout(basic_layout)
# ---------- 分组2:扩展信息 ----------
extend_group = QGroupBox("扩展信息(选填)")
extend_layout = QFormLayout()
extend_layout.setSpacing(15)
# 添加表单控件
extend_layout.addRow("邮箱:", QLineEdit())
extend_layout.addRow("地址:", QLineEdit())
extend_layout.addRow("备注:", QTextEdit())
# 绑定布局
extend_group.setLayout(extend_layout)
# 提交按钮
submit_btn = QPushButton("提交表单")
submit_btn.setFixedSize(100, 30)
# 添加到主布局
main_layout.addWidget(basic_group)
main_layout.addWidget(extend_group)
main_layout.addWidget(submit_btn, alignment=Qt.AlignCenter)
self.setLayout(main_layout)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = GroupBoxFormDemo()
window.show()
sys.exit(app.exec_())三、QTabWidget(标签页控件)详解:多页面切换
QTabWidget是“多页面”界面的核心控件,比如浏览器的标签页、软件的功能面板,核心是“一个窗口承载多个功能页面”,极大节省界面空间。
1. QTabWidget基础用法(完整代码)
实现包含“文本编辑页”“数据表格页”“设置页”的多标签窗口,演示标签页的添加、切换、删除等核心操作:
import sys
from PyQt5.QtWidgets import (
QApplication, QWidget, QVBoxLayout, QHBoxLayout,
QTabWidget, QTextEdit, QTableWidget, QTableWidgetItem,
QPushButton, QLabel, QComboBox
)
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import Qt
class TabWidgetDemo(QWidget):
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
self.setWindowTitle("QTabWidget标签页基础演示")
self.resize(800, 500)
# 主布局(垂直):标签页控件 + 操作按钮
main_layout = QVBoxLayout()
main_layout.setSpacing(15)
main_layout.setContentsMargins(15, 15, 15, 15)
# ---------- 创建QTabWidget核心控件 ----------
self.tab_widget = QTabWidget()
# 设置标签位置(可选:North/南South/东East/西West,默认North)
self.tab_widget.setTabPosition(QTabWidget.North)
# 允许关闭标签页(显示×按钮)
self.tab_widget.setTabsClosable(True)
# 标签栏可滚动(标签过多时显示左右箭头)
self.tab_widget.setTabBarAutoHide(False)
# ---------- 添加标签页 ----------
# 页1:文本编辑页
text_page = QWidget()
text_layout = QVBoxLayout(text_page)
text_edit = QTextEdit()
text_edit.setPlaceholderText("文本编辑页:在这里输入内容...")
text_layout.addWidget(text_edit)
# 添加标签页(参数:页面控件,标签文本,可选:图标)
self.tab_widget.addTab(text_page, "文本编辑")
# 页2:数据表格页
table_page = QWidget()
table_layout = QVBoxLayout(table_page)
table = QTableWidget()
table.setRowCount(5)
table.setColumnCount(4)
table.setHorizontalHeaderLabels(["ID", "姓名", "性别", "年龄"])
# 填充测试数据
test_data = [
[1, "张三", "男", 25],
[2, "李四", "女", 28],
[3, "王五", "男", 30],
[4, "赵六", "女", 22],
[5, "钱七", "男", 27]
]
for row in range(5):
for col in range(4):
item = QTableWidgetItem(str(test_data[row][col]))
item.setTextAlignment(Qt.AlignCenter)
table.setItem(row, col, item)
table_layout.addWidget(table)
self.tab_widget.addTab(table_page, "数据表格")
# 页3:设置页
setting_page = QWidget()
setting_layout = QVBoxLayout(setting_page)
# 设置页用水平布局放控件
setting_h_layout = QHBoxLayout()
setting_h_layout.addWidget(QLabel("主题:"))
setting_h_layout.addWidget(QComboBox())
setting_layout.addLayout(setting_h_layout)
setting_layout.addWidget(QLabel("设置页:在这里配置系统参数..."))
self.tab_widget.addTab(setting_page, "系统设置")
# ---------- 操作按钮区 ----------
btn_layout = QHBoxLayout()
add_tab_btn = QPushButton("添加新标签页")
close_tab_btn = QPushButton("关闭当前标签页")
switch_tab_btn = QPushButton("切换到设置页")
for btn in [add_tab_btn, close_tab_btn, switch_tab_btn]:
btn.setFixedSize(120, 30)
btn_layout.addWidget(add_tab_btn)
btn_layout.addWidget(close_tab_btn)
btn_layout.addWidget(switch_tab_btn)
btn_layout.addStretch()
# ---------- 绑定布局和信号 ----------
main_layout.addWidget(self.tab_widget)
main_layout.addLayout(btn_layout)
self.setLayout(main_layout)
# 信号绑定
add_tab_btn.clicked.connect(self.add_new_tab)
close_tab_btn.clicked.connect(self.close_current_tab)
switch_tab_btn.clicked.connect(self.switch_to_setting_tab)
# 标签页关闭信号(点击×按钮触发)
self.tab_widget.tabCloseRequested.connect(self.close_specified_tab)
# 标签页切换信号
self.tab_widget.currentChanged.connect(self.on_tab_changed)
# ---------- 标签页操作槽函数 ----------
def add_new_tab(self):
"""添加新的空白标签页"""
new_page = QWidget()
new_layout = QVBoxLayout(new_page)
new_layout.addWidget(QLabel("这是新添加的空白标签页"))
# 添加标签页(带自定义文本)
tab_index = self.tab_widget.addTab(new_page, f"新标签{self.tab_widget.count()+1}")
# 切换到新添加的标签页
self.tab_widget.setCurrentIndex(tab_index)
def close_current_tab(self):
"""关闭当前选中的标签页"""
current_index = self.tab_widget.currentIndex()
if current_index >= 0: # 确保有标签页可关闭
self.tab_widget.removeTab(current_index)
def close_specified_tab(self, index):
"""关闭指定索引的标签页(点击×按钮触发)"""
self.tab_widget.removeTab(index)
def switch_to_setting_tab(self):
"""切换到设置页(通过索引,设置页是第3个,索引为2)"""
self.tab_widget.setCurrentIndex(2)
def on_tab_changed(self, index):
"""标签页切换时触发,打印当前标签页名称"""
tab_text = self.tab_widget.tabText(index)
print(f"当前切换到:{tab_text}页")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = TabWidgetDemo()
window.show()
sys.exit(app.exec_())2. QTabWidget核心方法解析
QTabWidget的核心围绕“标签页的增删改查和切换”,重点掌握:
| 方法 | 作用 |
|---|---|
addTab(页面控件, 标签文本, 图标) | 添加标签页(返回新标签页的索引) |
insertTab(索引, 页面控件, 标签文本) | 在指定索引位置插入标签页 |
removeTab(索引) | 删除指定索引的标签页 |
setCurrentIndex(索引) | 切换到指定索引的标签页 |
currentIndex() | 获取当前选中的标签页索引 |
tabText(索引) | 获取指定索引标签页的文本 |
setTabPosition(位置) | 设置标签位置(North/South/East/West) |
setTabsClosable(True) | 显示标签页的关闭按钮(×) |
setTabIcon(索引, QIcon) | 给指定标签页设置图标 |
3. QTabWidget实战:带图标的标签页
给标签页添加图标(提升界面美观度),并实现“标签页内容自适应”:
图片素材
import sys
from PyQt5.QtWidgets import (
QApplication, QWidget, QVBoxLayout, QTabWidget,
QTextEdit, QTableWidget, QTableWidgetItem
)
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import Qt
# 注意:需提前准备3个图标文件(text.png、table.png、setting.png)放在同级目录
# 若无图标,可注释掉setTabIcon相关代码
# 本站提供素材图片下载
class TabWidgetIconDemo(QWidget):
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
self.setWindowTitle("QTabWidget带图标标签页实战")
self.resize(800, 500)
# 主布局
main_layout = QVBoxLayout()
self.tab_widget = QTabWidget()
# 页1:文本编辑页(带图标)
text_page = QWidget()
text_layout = QVBoxLayout(text_page)
text_layout.addWidget(QTextEdit("文本编辑页"))
self.tab_widget.addTab(text_page, "文本编辑")
# 设置图标
self.tab_widget.setTabIcon(0, QIcon("text.png"))
# 页2:数据表格页(带图标)
table_page = QWidget()
table_layout = QVBoxLayout(table_page)
table = QTableWidget(5, 4)
table.setHorizontalHeaderLabels(["ID", "姓名", "性别", "年龄"])
table_layout.addWidget(table)
self.tab_widget.addTab(table_page, "数据表格")
self.tab_widget.setTabIcon(1, QIcon("table.png"))
# 页3:设置页(带图标)
setting_page = QWidget()
setting_layout = QVBoxLayout(setting_page)
setting_layout.addWidget(QTextEdit("系统设置页"))
self.tab_widget.addTab(setting_page, "系统设置")
self.tab_widget.setTabIcon(2, QIcon("setting.png"))
# 标签页内容自适应
self.tab_widget.setSizePolicy(
self.tab_widget.sizePolicy().horizontalPolicy(),
self.tab_widget.sizePolicy().verticalPolicy()
)
main_layout.addWidget(self.tab_widget)
self.setLayout(main_layout)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = TabWidgetIconDemo()
window.show()
sys.exit(app.exec_())四、综合案例:多功能工具窗口(QTabWidget+QGroupBox)
整合QTabWidget(多页面)和QGroupBox(分组),实现一个“多功能工具窗口”——包含文本编辑页、数据表格页、设置页(设置页用QGroupBox分组),贴合实际项目的界面风格:
import sys
from PyQt5.QtWidgets import (
QApplication, QWidget, QVBoxLayout, QHBoxLayout,
QTabWidget, QTextEdit, QTableWidget, QTableWidgetItem,
QGroupBox, QLabel, QComboBox, QCheckBox, QPushButton,
QFileDialog, QMessageBox
)
from PyQt5.QtCore import Qt
class MultiToolWindow(QWidget):
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
self.setWindowTitle("多功能工具窗口(QTabWidget+QGroupBox)")
self.resize(800, 600)
# 主布局
main_layout = QVBoxLayout()
self.tab_widget = QTabWidget()
# ---------- 页1:文本编辑页 ----------
text_page = QWidget()
text_layout = QVBoxLayout(text_page)
# 文本编辑区
self.text_edit = QTextEdit()
self.text_edit.setPlaceholderText("请输入文本...")
# 操作按钮
text_btn_layout = QHBoxLayout()
open_btn = QPushButton("打开文件")
save_btn = QPushButton("保存文件")
for btn in [open_btn, save_btn]:
btn.setFixedSize(80, 30)
text_btn_layout.addWidget(open_btn)
text_btn_layout.addWidget(save_btn)
text_btn_layout.addStretch()
# 添加到文本页布局
text_layout.addLayout(text_btn_layout)
text_layout.addWidget(self.text_edit)
self.tab_widget.addTab(text_page, "文本编辑")
# ---------- 页2:数据表格页 ----------
table_page = QWidget()
table_layout = QVBoxLayout(table_page)
self.table = QTableWidget()
self.table.setRowCount(0)
self.table.setColumnCount(4)
self.table.setHorizontalHeaderLabels(["ID", "姓名", "性别", "年龄"])
table_layout.addWidget(self.table)
self.tab_widget.addTab(table_page, "数据表格")
# ---------- 页3:设置页(用QGroupBox分组) ----------
setting_page = QWidget()
setting_layout = QVBoxLayout(setting_page)
# 分组1:界面设置
ui_group = QGroupBox("界面设置")
ui_layout = QHBoxLayout()
ui_layout.addWidget(QLabel("主题:"))
ui_layout.addWidget(QComboBox())
ui_group.setLayout(ui_layout)
# 分组2:数据设置
data_group = QGroupBox("数据设置")
data_group.setCheckable(True)
data_layout = QHBoxLayout()
data_layout.addWidget(QCheckBox("自动保存"))
data_layout.addWidget(QCheckBox("自动同步"))
data_group.setLayout(data_layout)
# 保存设置按钮
save_setting_btn = QPushButton("保存设置")
save_setting_btn.setFixedSize(100, 30)
# 添加到设置页布局
setting_layout.addWidget(ui_group)
setting_layout.addWidget(data_group)
setting_layout.addWidget(save_setting_btn, alignment=Qt.AlignCenter)
self.tab_widget.addTab(setting_page, "系统设置")
# ---------- 绑定布局和信号 ----------
main_layout.addWidget(self.tab_widget)
self.setLayout(main_layout)
# 信号绑定
open_btn.clicked.connect(self.open_file)
save_btn.clicked.connect(self.save_file)
save_setting_btn.clicked.connect(self.save_setting)
# ---------- 文本页功能 ----------
def open_file(self):
file_path, _ = QFileDialog.getOpenFileName(self, "打开文件", "", "Text Files (*.txt)")
if file_path:
with open(file_path, "r", encoding="utf-8") as f:
self.text_edit.setText(f.read())
QMessageBox.information(self, "成功", "文件打开成功!")
def save_file(self):
file_path, _ = QFileDialog.getSaveFileName(self, "保存文件", "", "Text Files (*.txt)")
if file_path:
with open(file_path, "w", encoding="utf-8") as f:
f.write(self.text_edit.toPlainText())
QMessageBox.information(self, "成功", "文件保存成功!")
# ---------- 设置页功能 ----------
def save_setting(self):
QMessageBox.information(self, "成功", "设置保存成功!")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MultiToolWindow()
window.show()
sys.exit(app.exec_())五、常见问题排查
1. QGroupBox相关问题
- 问题1:分组框内控件排列混乱 → 解决:分组框必须绑定布局(如QVBoxLayout/QHBoxLayout),再将控件添加到布局,而非直接添加到分组框;
- 问题2:可勾选分组框勾选后内部控件仍禁用 → 解决:确保内部控件未手动设置
setEnabled(False),分组框的setCheckable(True)仅控制“是否可勾选”,setChecked(True)才会启用内部控件; - 问题3:分组框标题不显示 → 解决:检查
setTitle()是否传入空字符串,或样式表覆盖了标题显示(可重置样式表测试)。
2. QTabWidget相关问题
- 问题1:标签页内容不自适应窗口缩放 → 解决:标签页的页面控件(如QWidget)必须绑定布局,且布局内的控件未设置固定大小;
- 问题2:标签页关闭按钮不显示 → 解决:调用
setTabsClosable(True),且确保Qt版本支持(PyQt5 5.6+均支持); - 问题3:添加图标后标签页不显示图标 → 解决:检查图标路径是否正确(绝对路径/相对路径),图标格式是否支持(png/jpg/ico);
问题4:标签页切换无响应 → 解决:
currentChanged信号绑定的槽函数需检查参数(索引)是否正确,避免索引越界。总结
- QGroupBox:核心用于控件分组,提升界面可读性,支持“可勾选分组”(勾选启用内部控件),是表单/设置界面的必备工具;
- QTabWidget:核心用于多页面切换,节省界面空间,支持标签页增删改查、图标设置、关闭按钮等,是多功能窗口的核心控件;
- 组合使用:实际项目中常将QTabWidget(多页面)和QGroupBox(分组)结合,比如“设置页用QGroupBox分组,多个功能页用QTabWidget切换”;
- 下一章我们将进入阶段二的收尾——阶段二实战项目:仿照Excel简易表格数据管理器,整合布局管理器、表格控件、容器控件的核心知识点,完成一个完整的实战项目。
如果在容器控件开发中遇到界面排版、标签页切换的问题,或者想拓展更复杂的多标签功能(如拖拽标签页、标签页右键菜单),欢迎在评论区留言讨论~


