第7篇:PyQt5文本与表格控件:QTextEdit与QTableWidget(完整代码)
哈喽~ 欢迎来到PyQt5系列的第7篇!上一章我们掌握了网格布局和表单布局,解决了复杂界面的排版问题。今天我们聚焦两个高频实用控件:QTextEdit(多行富文本编辑控件)和QTableWidget(表格控件)——这两个控件是处理“大段文本”和“结构化数据”的核心,比如文本编辑器、数据管理系统、报表展示等场景都离不开它们。全程搭配完整可运行代码,新手也能轻松掌握!
一、先明确:两个控件的核心定位
在学习具体用法前,先理清这两个控件的适用场景,避免用错:
- 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,如需编辑改为DoubleClicked或AllEditTriggers。
总结
- QTextEdit:核心用于多行文本/富文本处理,支持纯文本和HTML格式,
mergeCurrentCharFormat是设置富文本格式的核心方法; - QTableWidget:核心用于结构化数据展示/编辑,重点掌握行列管理、单元格操作、数据导入导出;
- 两个控件常结合使用(如表格展示列表+文本区展示详情),是数据管理类应用的核心组合;
- 下一章我们将学习PyQt5的对话框控件(QDialog),包括标准对话框和自定义对话框,进一步完善界面的交互能力。
如果在实操中遇到文本/表格处理的问题,或者想拓展更复杂的功能(如表格单元格合并、富文本插入图片),欢迎在评论区留言讨论~