PyQt5容器控件:QTabWidget与QGroupBox(附多功能窗口实战)

寒烟似雪
1月5日发布 /正在检测是否收录...

第9篇:PyQt5容器控件:QTabWidget与QGroupBox(完整代码)

哈喽~ 欢迎来到PyQt5系列的第9篇!上一章我们掌握了QDialog和各类标准对话框,解决了界面的交互弹窗问题。今天我们聚焦容器控件——这类控件的核心作用是“管理其他控件”,把功能相关的控件分组/分页面摆放,让复杂界面更规整、层次感更强。我们会详细讲解两种高频容器控件:QGroupBox(分组框)和QTabWidget(标签页控件),全程搭配完整可运行代码,新手也能轻松掌握!
mk0o8rmi.png

一、先明确:容器控件的核心定位

容器控件本身不实现业务功能,而是作为“控件的容器”存在,核心价值是提升界面的结构化和可读性

  • QGroupBox(分组框):把功能相关的控件(如设置项、表单字段)“分组”展示,带标题和可选边框,用户能快速识别控件的功能归属;
  • QTabWidget(标签页控件):把不同功能模块(如文本编辑、数据表格、系统设置)“分页面”展示,通过点击标签切换页面,极大节省界面空间,适合多功能集成的窗口。

二、QGroupBox(分组框)详解:控件分组管理

QGroupBox是最基础的容器控件,核心是“给控件加分组标题+边框”,支持“可勾选分组”(勾选后才启用内部控件),是规整表单/设置界面的必备工具。

1. QGroupBox基础用法(完整代码)

实现两个分组框(“界面设置”和“数据设置”),演示分组框的基础属性和可勾选功能:
mk0ns3om.png

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将用户表单分为“基础信息”和“扩展信息”两组,提升表单可读性:
mk0nukbw.png

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基础用法(完整代码)

实现包含“文本编辑页”“数据表格页”“设置页”的多标签窗口,演示标签页的添加、切换、删除等核心操作:
mk0nwa5q.png

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实战:带图标的标签页

给标签页添加图标(提升界面美观度),并实现“标签页内容自适应”:
mk0o39iv.png

图片素材

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分组),贴合实际项目的界面风格:
mk0o7d0r.png

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简易表格数据管理器,整合布局管理器、表格控件、容器控件的核心知识点,完成一个完整的实战项目。

如果在容器控件开发中遇到界面排版、标签页切换的问题,或者想拓展更复杂的多标签功能(如拖拽标签页、标签页右键菜单),欢迎在评论区留言讨论~

© 版权声明
THE END
喜欢就支持一下吧
点赞 0 分享 收藏
评论 抢沙发
OωO
取消
SSL