PyQt5文本与表格控件:QTextEdit与QTableWidget(附实战代码)

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

第7篇:PyQt5文本与表格控件:QTextEdit与QTableWidget(完整代码)

哈喽~ 欢迎来到PyQt5系列的第7篇!上一章我们掌握了网格布局和表单布局,解决了复杂界面的排版问题。今天我们聚焦两个高频实用控件:QTextEdit(多行富文本编辑控件)和QTableWidget(表格控件)——这两个控件是处理“大段文本”和“结构化数据”的核心,比如文本编辑器、数据管理系统、报表展示等场景都离不开它们。全程搭配完整可运行代码,新手也能轻松掌握!
mjxm4a2v.png

一、先明确:两个控件的核心定位

在学习具体用法前,先理清这两个控件的适用场景,避免用错:

  • QTextEdit:多行文本编辑/展示控件,支持富文本(字体、颜色、图片、超链接),比QLineEdit(单行)功能强大,核心用于“大段文本处理”(如记事本、富文本编辑器);
  • QTableWidget:表格控件,支持行/列的增删改查、单元格编辑、数据排序,核心用于“结构化数据展示/编辑”(如Excel简易表格、用户信息列表)。

二、QTextEdit详解:从基础文本到富文本编辑

QTextEdit是阶段一“简易记事本”中用到的核心控件,但当时只用到了基础文本功能,这一节我们深挖它的富文本能力。

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

先回顾基础功能,再拓展富文本设置:

import sys
from PyQt5.QtWidgets import (
    QApplication, QWidget, QTextEdit, QVBoxLayout,
    QPushButton, QHBoxLayout, QColorDialog, QFontDialog
)
from PyQt5.QtGui import QTextCharFormat, QFont, QColor
from PyQt5.QtCore import Qt

class TextEditDemo(QWidget):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        self.setWindowTitle("QTextEdit基础与富文本演示")
        self.resize(600, 400)

        # 1. 主布局(垂直):按钮区 + 文本编辑区
        main_layout = QVBoxLayout()
        main_layout.setSpacing(10)
        main_layout.setContentsMargins(15, 15, 15, 15)

        # 2. 功能按钮区(水平布局)
        btn_layout = QHBoxLayout()
        btn_layout.setSpacing(8)

        # 富文本功能按钮
        self.bold_btn = QPushButton("加粗")
        self.italic_btn = QPushButton("斜体")
        self.color_btn = QPushButton("字体颜色")
        self.font_btn = QPushButton("选择字体")
        self.clear_btn = QPushButton("清空文本")

        # 按钮样式
        btn_size = (80, 30)
        for btn in [self.bold_btn, self.italic_btn, self.color_btn, self.font_btn, self.clear_btn]:
            btn.setFixedSize(*btn_size)

        # 添加到按钮布局
        btn_layout.addWidget(self.bold_btn)
        btn_layout.addWidget(self.italic_btn)
        btn_layout.addWidget(self.color_btn)
        btn_layout.addWidget(self.font_btn)
        btn_layout.addStretch()  # 伸缩空间
        btn_layout.addWidget(self.clear_btn)

        # 3. 创建QTextEdit控件
        self.text_edit = QTextEdit()
        # 基础设置:默认提示文本、字体
        self.text_edit.setPlaceholderText("请输入文本(支持富文本格式:加粗、斜体、改颜色等)")
        self.text_edit.setFont(QFont("微软雅黑", 12))
        # 允许自动换行
        self.text_edit.setLineWrapMode(QTextEdit.WidgetWidth)

        # 4. 添加到主布局
        main_layout.addLayout(btn_layout)
        main_layout.addWidget(self.text_edit)

        # 5. 绑定布局和信号
        self.setLayout(main_layout)
        self.bind_signals()

    def bind_signals(self):
        """绑定信号与槽"""
        self.bold_btn.clicked.connect(self.set_bold)
        self.italic_btn.clicked.connect(self.set_italic)
        self.color_btn.clicked.connect(self.set_font_color)
        self.font_btn.clicked.connect(self.choose_font)
        self.clear_btn.clicked.connect(self.text_edit.clear)

    def set_bold(self):
        """设置选中文本加粗/取消加粗"""
        # 获取当前光标选中的文本格式
        fmt = QTextCharFormat()
        # 切换加粗状态:当前加粗则取消,反之则加粗
        fmt.setFontWeight(QFont.Bold if self.text_edit.fontWeight() != QFont.Bold else QFont.Normal)
        # 应用格式到选中文本
        self.text_edit.mergeCurrentCharFormat(fmt)

    def set_italic(self):
        """设置选中文本斜体/取消斜体"""
        fmt = QTextCharFormat()
        fmt.setFontItalic(not self.text_edit.fontItalic())
        self.text_edit.mergeCurrentCharFormat(fmt)

    def set_font_color(self):
        """选择字体颜色并应用到选中文本"""
        # 弹出颜色选择对话框
        color = QColorDialog.getColor(Qt.black, self, "选择字体颜色")
        if color.isValid():  # 用户选择了有效颜色
            fmt = QTextCharFormat()
            fmt.setForeground(color)
            self.text_edit.mergeCurrentCharFormat(fmt)

    def choose_font(self):
        """选择字体(字体名、大小、样式)"""
        # 弹出字体选择对话框
        font, ok = QFontDialog.getFont(self.text_edit.font(), self, "选择字体")
        if ok:  # 用户确认选择
            self.text_edit.setCurrentFont(font)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = TextEditDemo()
    window.show()
    sys.exit(app.exec_())

2. QTextEdit核心方法解析

QTextEdit的核心分为“文本操作”和“格式设置”两类,重点掌握以下方法:

(1)基础文本操作

方法作用
toPlainText()获取纯文本内容(忽略富文本格式)
setPlainText(文本)设置纯文本内容(覆盖原有内容)
toHtml()获取富文本内容(HTML格式)
setHtml(HTML文本)设置富文本内容(支持HTML标签)
append(文本)在末尾追加文本(保留原有格式)
clear()清空所有文本
undo()/redo()撤销/重做操作

(2)富文本格式设置

方法作用
mergeCurrentCharFormat(格式对象)将格式应用到选中的文本
setCurrentFont(字体对象)设置当前光标位置/选中文本的字体
setFontWeight(QFont.Bold/Normal)设置加粗/取消加粗
setFontItalic(True/False)设置斜体/取消斜体
setForeground(QColor)设置字体颜色

3. QTextEdit实战:简易富文本编辑器

基于基础用法,拓展一个带“打开/保存富文本”功能的编辑器,支持保存为HTML格式(保留富文本样式):

import sys
import os
from PyQt5.QtWidgets import (
    QApplication, QWidget, QTextEdit, QVBoxLayout,
    QPushButton, QHBoxLayout, QColorDialog, QFontDialog,
    QFileDialog
)
from PyQt5.QtGui import QTextCharFormat, QFont, QColor
from PyQt5.QtCore import Qt

class RichTextEditor(QWidget):
    def __init__(self):
        super().__init__()
        self.init_ui()
        self.current_file_path = None  # 记录当前文件路径

    def init_ui(self):
        self.setWindowTitle("简易富文本编辑器")
        self.resize(800, 600)

        # 1. 主布局
        main_layout = QVBoxLayout()
        main_layout.setSpacing(10)
        main_layout.setContentsMargins(15, 15, 15, 15)

        # 2. 顶部功能按钮区
        top_btn_layout = QHBoxLayout()
        self.new_btn = QPushButton("新建")
        self.open_btn = QPushButton("打开")
        self.save_btn = QPushButton("保存")
        for btn in [self.new_btn, self.open_btn, self.save_btn]:
            btn.setFixedSize(80, 30)
        top_btn_layout.addWidget(self.new_btn)
        top_btn_layout.addWidget(self.open_btn)
        top_btn_layout.addWidget(self.save_btn)
        top_btn_layout.addStretch()

        # 3. 格式设置按钮区
        fmt_btn_layout = QHBoxLayout()
        self.bold_btn = QPushButton("加粗")
        self.italic_btn = QPushButton("斜体")
        self.color_btn = QPushButton("字体颜色")
        self.font_btn = QPushButton("选择字体")
        for btn in [self.bold_btn, self.italic_btn, self.color_btn, self.font_btn]:
            btn.setFixedSize(80, 30)
        fmt_btn_layout.addWidget(self.bold_btn)
        fmt_btn_layout.addWidget(self.italic_btn)
        fmt_btn_layout.addWidget(self.color_btn)
        fmt_btn_layout.addWidget(self.font_btn)
        fmt_btn_layout.addStretch()

        # 4. 文本编辑区
        self.text_edit = QTextEdit()
        self.text_edit.setFont(QFont("微软雅黑", 12))

        # 5. 添加到主布局
        main_layout.addLayout(top_btn_layout)
        main_layout.addLayout(fmt_btn_layout)
        main_layout.addWidget(self.text_edit)

        # 6. 绑定布局和信号
        self.setLayout(main_layout)
        self.bind_signals()

    def bind_signals(self):
        """绑定所有信号与槽"""
        # 文件操作
        self.new_btn.clicked.connect(self.on_new)
        self.open_btn.clicked.connect(self.on_open)
        self.save_btn.clicked.connect(self.on_save)
        # 格式操作
        self.bold_btn.clicked.connect(self.set_bold)
        self.italic_btn.clicked.connect(self.set_italic)
        self.color_btn.clicked.connect(self.set_font_color)
        self.font_btn.clicked.connect(self.choose_font)

    # ---------- 文件操作槽函数 ----------
    def on_new(self):
        """新建文件:清空文本,重置路径"""
        self.text_edit.clear()
        self.current_file_path = None
        self.setWindowTitle("简易富文本编辑器 - 未保存文件")

    def on_open(self):
        """打开文件:支持txt(纯文本)和html(富文本)"""
        file_path, _ = QFileDialog.getOpenFileName(
            self, "打开文件", "", "HTML Files (*.html);;Text Files (*.txt);;All Files (*.*)"
        )
        if file_path and os.path.exists(file_path):
            self.current_file_path = file_path
            # 根据后缀选择读取方式
            if file_path.endswith(".html"):
                with open(file_path, "r", encoding="utf-8") as f:
                    content = f.read()
                self.text_edit.setHtml(content)
            else:
                with open(file_path, "r", encoding="utf-8") as f:
                    content = f.read()
                self.text_edit.setPlainText(content)
            # 更新窗口标题
            self.setWindowTitle(f"简易富文本编辑器 - {os.path.basename(file_path)}")

    def on_save(self):
        """保存文件:默认保存为HTML(保留富文本格式)"""
        if self.current_file_path:
            # 直接保存
            self.save_file(self.current_file_path)
        else:
            # 弹出保存对话框
            file_path, _ = QFileDialog.getSaveFileName(
                self, "保存文件", "", "HTML Files (*.html);;Text Files (*.txt)"
            )
            if file_path:
                # 补充后缀
                if not (file_path.endswith(".html") or file_path.endswith(".txt")):
                    file_path += ".html"
                self.save_file(file_path)
                self.current_file_path = file_path
                self.setWindowTitle(f"简易富文本编辑器 - {os.path.basename(file_path)}")

    def save_file(self, file_path):
        """辅助函数:保存文件"""
        if file_path.endswith(".html"):
            content = self.text_edit.toHtml()
        else:
            content = self.text_edit.toPlainText()
        with open(file_path, "w", encoding="utf-8") as f:
            f.write(content)

    # ---------- 格式设置槽函数 ----------
    def set_bold(self):
        fmt = QTextCharFormat()
        fmt.setFontWeight(QFont.Bold if self.text_edit.fontWeight() != QFont.Bold else QFont.Normal)
        self.text_edit.mergeCurrentCharFormat(fmt)

    def set_italic(self):
        fmt = QTextCharFormat()
        fmt.setFontItalic(not self.text_edit.fontItalic())
        self.text_edit.mergeCurrentCharFormat(fmt)

    def set_font_color(self):
        color = QColorDialog.getColor(Qt.black, self, "选择字体颜色")
        if color.isValid():
            fmt = QTextCharFormat()
            fmt.setForeground(color)
            self.text_edit.mergeCurrentCharFormat(fmt)

    def choose_font(self):
        font, ok = QFontDialog.getFont(self.text_edit.font(), self, "选择字体")
        if ok:
            self.text_edit.setCurrentFont(font)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    editor = RichTextEditor()
    editor.show()
    sys.exit(app.exec_())

三、QTableWidget详解:结构化数据的展示与编辑

QTableWidget是处理表格数据的核心控件,支持行/列管理、单元格编辑、数据排序,是实现“数据表格”的首选。

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

先实现一个基础表格,演示行/列添加、单元格赋值、选中行获取等核心操作:

import sys
from PyQt5.QtWidgets import (
    QApplication, QWidget, QTableWidget, QTableWidgetItem,
    QVBoxLayout, QHBoxLayout, QPushButton, QMessageBox
)
from PyQt5.QtCore import Qt

class TableWidgetDemo(QWidget):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        self.setWindowTitle("QTableWidget基础演示")
        self.resize(600, 400)

        # 1. 主布局:按钮区 + 表格区
        main_layout = QVBoxLayout()
        main_layout.setSpacing(15)
        main_layout.setContentsMargins(15, 15, 15, 15)

        # 2. 功能按钮区
        btn_layout = QHBoxLayout()
        self.add_row_btn = QPushButton("添加行")
        self.del_row_btn = QPushButton("删除选中行")
        self.get_data_btn = QPushButton("获取选中行数据")
        self.clear_btn = QPushButton("清空表格")
        for btn in [self.add_row_btn, self.del_row_btn, self.get_data_btn, self.clear_btn]:
            btn.setFixedSize(100, 30)
        btn_layout.addWidget(self.add_row_btn)
        btn_layout.addWidget(self.del_row_btn)
        btn_layout.addWidget(self.get_data_btn)
        btn_layout.addWidget(self.clear_btn)
        btn_layout.addStretch()

        # 3. 创建QTableWidget控件
        self.table = QTableWidget()
        # 设置表格行列数:5行4列
        self.table.setRowCount(5)
        self.table.setColumnCount(4)
        # 设置列标题
        self.table.setHorizontalHeaderLabels(["ID", "姓名", "性别", "年龄"])
        # 可选设置:列宽自适应、行高自适应、禁止编辑(默认允许)
        self.table.horizontalHeader().setStretchLastSection(True)  # 最后一列拉伸
        self.table.verticalHeader().setVisible(False)  # 隐藏行号
        # self.table.setEditTriggers(QTableWidget.NoEditTriggers)  # 禁止编辑单元格

        # 4. 填充初始数据
        init_data = [
            [1, "张三", "男", 25],
            [2, "李四", "女", 28],
            [3, "王五", "男", 30],
            [4, "赵六", "女", 22],
            [5, "钱七", "男", 27]
        ]
        for row in range(len(init_data)):
            for col in range(len(init_data[row])):
                # 创建表格项(设置居中对齐)
                item = QTableWidgetItem(str(init_data[row][col]))
                item.setTextAlignment(Qt.AlignCenter)
                # 将项添加到表格
                self.table.setItem(row, col, item)

        # 5. 添加到主布局
        main_layout.addLayout(btn_layout)
        main_layout.addWidget(self.table)

        # 6. 绑定布局和信号
        self.setLayout(main_layout)
        self.bind_signals()

    def bind_signals(self):
        """绑定信号与槽"""
        self.add_row_btn.clicked.connect(self.add_row)
        self.del_row_btn.clicked.connect(self.del_selected_row)
        self.get_data_btn.clicked.connect(self.get_selected_data)
        self.clear_btn.clicked.connect(self.clear_table)

    def add_row(self):
        """添加一行空数据"""
        # 获取当前行数,在末尾添加新行
        current_row = self.table.rowCount()
        self.table.insertRow(current_row)
        # 给新行ID列赋值(自增)
        id_item = QTableWidgetItem(str(current_row + 1))
        id_item.setTextAlignment(Qt.AlignCenter)
        self.table.setItem(current_row, 0, id_item)

    def del_selected_row(self):
        """删除选中的行"""
        # 获取选中的行号(单个选中)
        selected_rows = self.table.selectedItems()
        if not selected_rows:
            QMessageBox.warning(self, "提示", "请先选中要删除的行!")
            return
        # 获取选中行的行号(取第一个选中项的行号)
        row = selected_rows[0].row()
        self.table.removeRow(row)

    def get_selected_data(self):
        """获取选中行的所有数据"""
        selected_rows = self.table.selectedItems()
        if not selected_rows:
            QMessageBox.warning(self, "提示", "请先选中一行!")
            return
        # 提取选中行的所有列数据
        row = selected_rows[0].row()
        data = []
        for col in range(self.table.columnCount()):
            item = self.table.item(row, col)
            data.append(item.text() if item else "")
        # 显示数据
        QMessageBox.information(self, "选中行数据", 
                                f"ID:{data[0]}\n姓名:{data[1]}\n性别:{data[2]}\n年龄:{data[3]}")

    def clear_table(self):
        """清空表格(保留列标题)"""
        self.table.setRowCount(0)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = TableWidgetDemo()
    window.show()
    sys.exit(app.exec_())

2. QTableWidget核心方法解析

QTableWidget的核心围绕“行/列管理”和“单元格操作”,重点掌握:

(1)行列管理

方法作用
setRowCount(行数)设置表格行数
setColumnCount(列数)设置表格列数
setHorizontalHeaderLabels([列标题列表])设置列标题
insertRow(行号)在指定行号位置插入新行
removeRow(行号)删除指定行
setRowCount(0)清空所有行(保留列标题)

(2)单元格操作

方法作用
setItem(行号, 列号, QTableWidgetItem)给指定单元格设置内容
item(行号, 列号)获取指定单元格的项
selectedItems()获取所有选中的单元格项
setEditTriggers(触发方式)设置单元格编辑触发方式(如NoEditTriggers禁止编辑)
setTextAlignment(对齐方式)设置单元格文本对齐(如Qt.AlignCenter居中)

(3)样式/布局优化

方法作用
horizontalHeader().setStretchLastSection(True)最后一列自适应拉伸
verticalHeader().setVisible(False)隐藏行号
setColumnWidth(列号, 宽度)设置指定列的宽度
setRowHeight(行号, 高度)设置指定行的高度

3. QTableWidget实战:简易数据表格管理器

拓展一个带“导入/导出数据”(CSV格式)、“数据排序”功能的表格管理器,贴合实际数据管理场景:

import sys
import os
import csv
from PyQt5.QtWidgets import (
    QApplication, QWidget, QTableWidget, QTableWidgetItem,
    QVBoxLayout, QHBoxLayout, QPushButton, QMessageBox,
    QFileDialog, QComboBox
)
from PyQt5.QtCore import Qt

class TableManager(QWidget):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        self.setWindowTitle("简易数据表格管理器")
        self.resize(700, 500)

        # 1. 主布局
        main_layout = QVBoxLayout()
        main_layout.setSpacing(15)
        main_layout.setContentsMargins(15, 15, 15, 15)

        # 2. 顶部功能区(导入/导出 + 排序)
        top_layout = QHBoxLayout()
        # 导入/导出按钮
        self.import_btn = QPushButton("导入CSV")
        self.export_btn = QPushButton("导出CSV")
        # 排序下拉框
        self.sort_combo = QComboBox()
        self.sort_combo.addItems(["按ID升序", "按年龄升序", "按年龄降序"])
        self.sort_btn = QPushButton("排序")
        # 样式设置
        for btn in [self.import_btn, self.export_btn, self.sort_btn]:
            btn.setFixedSize(100, 30)
        self.sort_combo.setFixedWidth(120)
        # 添加到布局
        top_layout.addWidget(self.import_btn)
        top_layout.addWidget(self.export_btn)
        top_layout.addStretch()
        top_layout.addWidget(self.sort_combo)
        top_layout.addWidget(self.sort_btn)

        # 3. 表格区
        self.table = QTableWidget()
        # 初始列标题
        self.table.setColumnCount(4)
        self.table.setHorizontalHeaderLabels(["ID", "姓名", "性别", "年龄"])
        # 布局优化
        self.table.horizontalHeader().setStretchLastSection(True)
        self.table.verticalHeader().setVisible(False)

        # 4. 添加到主布局
        main_layout.addLayout(top_layout)
        main_layout.addWidget(self.table)

        # 5. 绑定信号
        self.setLayout(main_layout)
        self.bind_signals()

    def bind_signals(self):
        self.import_btn.clicked.connect(self.import_csv)
        self.export_btn.clicked.connect(self.export_csv)
        self.sort_btn.clicked.connect(self.sort_data)

    # ---------- CSV导入导出 ----------
    def import_csv(self):
        """导入CSV文件到表格"""
        file_path, _ = QFileDialog.getOpenFileName(
            self, "导入CSV文件", "", "CSV Files (*.csv);;All Files (*.*)"
        )
        if not file_path:
            return
        try:
            # 清空原有数据
            self.table.setRowCount(0)
            # 读取CSV文件
            with open(file_path, "r", encoding="utf-8") as f:
                reader = csv.reader(f)
                # 跳过表头(如果CSV有表头)
                # next(reader)
                # 逐行添加数据
                for row_idx, row_data in enumerate(reader):
                    self.table.insertRow(row_idx)
                    for col_idx, col_data in enumerate(row_data):
                        item = QTableWidgetItem(col_data)
                        item.setTextAlignment(Qt.AlignCenter)
                        self.table.setItem(row_idx, col_idx, item)
            QMessageBox.information(self, "成功", "CSV文件导入成功!")
        except Exception as e:
            QMessageBox.critical(self, "错误", f"导入失败:{str(e)}")

    def export_csv(self):
        """导出表格数据到CSV"""
        file_path, _ = QFileDialog.getSaveFileName(
            self, "导出CSV文件", "", "CSV Files (*.csv)"
        )
        if not file_path:
            return
        # 补充.csv后缀
        if not file_path.endswith(".csv"):
            file_path += ".csv"
        try:
            # 写入CSV文件
            with open(file_path, "w", encoding="utf-8", newline="") as f:
                writer = csv.writer(f)
                # 写入表头
                headers = [self.table.horizontalHeaderItem(col).text() for col in range(self.table.columnCount())]
                writer.writerow(headers)
                # 写入数据
                for row in range(self.table.rowCount()):
                    row_data = []
                    for col in range(self.table.columnCount()):
                        item = self.table.item(row, col)
                        row_data.append(item.text() if item else "")
                    writer.writerow(row_data)
            QMessageBox.information(self, "成功", "CSV文件导出成功!")
        except Exception as e:
            QMessageBox.critical(self, "错误", f"导出失败:{str(e)}")

    # ---------- 数据排序 ----------
    def sort_data(self):
        """按选择的规则排序"""
        sort_type = self.sort_combo.currentText()
        if sort_type == "按ID升序":
            # 按第0列(ID)升序排序
            self.table.sortItems(0, Qt.AscendingOrder)
        elif sort_type == "按年龄升序":
            # 按第3列(年龄)升序排序
            self.table.sortItems(3, Qt.AscendingOrder)
        elif sort_type == "按年龄降序":
            # 按第3列(年龄)降序排序
            self.table.sortItems(3, Qt.DescendingOrder)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    manager = TableManager()
    manager.show()
    sys.exit(app.exec_())

四、综合案例:文本+表格的信息管理窗口

整合QTextEdit和QTableWidget,实现一个“用户信息管理窗口”——表格展示用户列表,选中用户后在文本区显示详情,支持编辑详情并保存:

import sys
from PyQt5.QtWidgets import (
    QApplication, QWidget, QTableWidget, QTableWidgetItem,
    QVBoxLayout, QHBoxLayout, QPushButton, QTextEdit,
    QMessageBox, QSplitter
)
from PyQt5.QtCore import Qt, QSize

class InfoManager(QWidget):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        self.setWindowTitle("用户信息管理窗口(文本+表格综合)")
        self.resize(800, 500)

        # 1. 创建分割器(左右布局,可拖动调整宽度)
        splitter = QSplitter(Qt.Horizontal)

        # 2. 左侧表格区
        self.table = QTableWidget()
        self.table.setColumnCount(3)
        self.table.setHorizontalHeaderLabels(["ID", "姓名", "性别"])
        self.table.horizontalHeader().setStretchLastSection(True)
        self.table.verticalHeader().setVisible(False)
        # 填充测试数据
        test_data = [[1, "张三", "男"], [2, "李四", "女"], [3, "王五", "男"]]
        for row in range(len(test_data)):
            self.table.insertRow(row)
            for col in range(len(test_data[row])):
                item = QTableWidgetItem(str(test_data[row][col]))
                item.setTextAlignment(Qt.AlignCenter)
                self.table.setItem(row, col, item)

        # 3. 右侧文本区(详情编辑)
        right_widget = QWidget()
        right_layout = QVBoxLayout(right_widget)
        # 文本编辑区
        self.info_edit = QTextEdit()
        self.info_edit.setPlaceholderText("选中表格中的用户,查看/编辑详情...")
        self.info_edit.setFont(QtGui.QFont("微软雅黑", 11))
        # 保存按钮
        save_btn = QPushButton("保存详情")
        save_btn.setFixedSize(100, 30)
        # 添加到右侧布局
        right_layout.addWidget(self.info_edit)
        right_layout.addWidget(save_btn, alignment=Qt.AlignCenter)

        # 4. 将表格和右侧控件添加到分割器
        splitter.addWidget(self.table)
        splitter.addWidget(right_widget)
        # 设置分割器初始宽度比例
        splitter.setSizes([300, 500])

        # 5. 主布局
        main_layout = QVBoxLayout()
        main_layout.addWidget(splitter)
        self.setLayout(main_layout)

        # 6. 绑定信号
        self.table.clicked.connect(self.show_user_info)
        save_btn.clicked.connect(self.save_user_info)

    def show_user_info(self):
        """选中表格行,显示用户详情"""
        selected_items = self.table.selectedItems()
        if not selected_items:
            return
        row = selected_items[0].row()
        # 获取用户基础信息
        user_id = self.table.item(row, 0).text()
        name = self.table.item(row, 1).text()
        gender = self.table.item(row, 2).text()
        # 构造详情文本
        info = f"""用户详情(ID:{user_id})
姓名:{name}
性别:{gender}
年龄:暂未填写
电话:暂未填写
邮箱:暂未填写
备注:无
"""
        self.info_edit.setPlainText(info)

    def save_user_info(self):
        """保存编辑后的详情"""
        if not self.info_edit.toPlainText():
            QMessageBox.warning(self, "提示", "详情不能为空!")
            return
        QMessageBox.information(self, "成功", "用户详情保存成功!")
        # 实际项目中可将详情写入数据库/文件

if __name__ == "__main__":
    app = QApplication(sys.argv)
    manager = InfoManager()
    manager.show()
    sys.exit(app.exec_())

五、常见问题排查

1. QTextEdit相关问题

  • 问题1:富文本格式设置不生效 → 解决:确保先选中文本再点击格式按钮;检查mergeCurrentCharFormat是否正确传入格式对象;
  • 问题2:保存的HTML文件打开乱码 → 解决:保存时指定encoding="utf-8"
  • 问题3:文本编辑区不自适应窗口缩放 → 解决:确保文本编辑区直接添加到垂直布局,未设置固定大小。

2. QTableWidget相关问题

  • 问题1:表格数据显示不全 → 解决:用horizontalHeader().setStretchLastSection(True)让最后一列拉伸;或手动设置列宽setColumnWidth
  • 问题2:选中行获取不到数据 → 解决:selectedItems()返回的是选中的单元格列表,需通过item.row()获取行号,再遍历列获取整行数据;
  • 问题3:CSV导入/导出乱码 → 解决:读写CSV时指定encoding="utf-8";Windows系统可尝试encoding="gbk"
  • 问题4:单元格无法编辑 → 解决:检查setEditTriggers是否设置为NoEditTriggers,如需编辑改为DoubleClickedAllEditTriggers

总结

  1. QTextEdit:核心用于多行文本/富文本处理,支持纯文本和HTML格式,mergeCurrentCharFormat是设置富文本格式的核心方法;
  2. QTableWidget:核心用于结构化数据展示/编辑,重点掌握行列管理、单元格操作、数据导入导出;
  3. 两个控件常结合使用(如表格展示列表+文本区展示详情),是数据管理类应用的核心组合;
  4. 下一章我们将学习PyQt5的对话框控件(QDialog),包括标准对话框和自定义对话框,进一步完善界面的交互能力。

如果在实操中遇到文本/表格处理的问题,或者想拓展更复杂的功能(如表格单元格合并、富文本插入图片),欢迎在评论区留言讨论~

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