如何在QTableView中设置选中文本的颜色与样式
QTableView单元格富文本编辑与渲染解决方案
问题需求
在QTableView的指定列实现富文本编辑功能:
- 支持选中文本设置格式(加粗、斜体、下划线、字号、颜色)
- 绑定快捷键(如Ctrl+B实现加粗)或工具栏按钮
- 富文本数据可保存回SQLite数据库,且单元格能正确渲染富文本样式
修改后的完整代码
import sys import os import sqlite3 from PyQt5.QtSql import * from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import * # 初始化数据库(首次运行取消注释) # con_1 = sqlite3.connect("temp.db") # con_1.execute('''create table t1( # id INTEGER PRIMARY KEY, 'First Name' TEXT, 'Last Name' TEXT, 'Full Name' TEXT);''') # con_1.execute("insert into t1 ('First Name', 'Last Name', 'Full Name') values('Wade', 'Wilson', '<b>Wade</b> Wilson');") # con_1.execute("insert into t1 ('First Name', 'Last Name', 'Full Name') values('Norman', 'Osborn', '<i>Norman Osborn</i>');") # con_1.execute("insert into t1 ('First Name', 'Last Name', 'Full Name') values('Stephen', 'Strange', '<span style=\"color:blue; font-size:14pt\">Stephen Strange</span>');") # con_1.commit() # con_1.close() class RichTextDelegate(QStyledItemDelegate): def createEditor(self, parent, option, index): editor = QTextEdit(parent) # 启用富文本编辑(默认已启用,显式设置更明确) editor.setAcceptRichText(True) # 绑定快捷键:Ctrl+B加粗,Ctrl+I斜体,Ctrl+U下划线 bold_shortcut = QShortcut(QKeySequence("Ctrl+B"), editor) bold_shortcut.activated.connect(lambda: self.toggle_format(editor, QTextCharFormat.FontWeight, QFont.Bold)) italic_shortcut = QShortcut(QKeySequence("Ctrl+I"), editor) italic_shortcut.activated.connect(lambda: self.toggle_format(editor, QTextCharFormat.FontItalic, True)) underline_shortcut = QShortcut(QKeySequence("Ctrl+U"), editor) underline_shortcut.activated.connect(lambda: self.toggle_format(editor, QTextCharFormat.UnderlineStyle, QTextCharFormat.SingleUnderline)) return editor def toggle_format(self, editor, format_property, target_value): cursor = editor.textCursor() if not cursor.hasSelection(): return fmt = QTextCharFormat() current_value = cursor.charFormat().property(format_property) # 切换格式:如果当前是目标值则取消,否则设置 if current_value == target_value: if format_property == QTextCharFormat.FontWeight: fmt.setFontWeight(QFont.Normal) elif format_property == QTextCharFormat.FontItalic: fmt.setFontItalic(False) elif format_property == QTextCharFormat.UnderlineStyle: fmt.setUnderlineStyle(QTextCharFormat.NoUnderline) else: if format_property == QTextCharFormat.FontWeight: fmt.setFontWeight(target_value) elif format_property == QTextCharFormat.FontItalic: fmt.setFontItalic(target_value) elif format_property == QTextCharFormat.UnderlineStyle: fmt.setUnderlineStyle(target_value) cursor.mergeCharFormat(fmt) editor.setTextCursor(cursor) def setEditorData(self, editor, index): # 从模型加载HTML格式的富文本 html_content = index.data(Qt.DisplayRole) or "" editor.setHtml(html_content) def setModelData(self, editor, model, index): # 将编辑器的HTML内容保存回模型(最终存入数据库) html_content = editor.toHtml() model.setData(index, html_content, Qt.EditRole) def paint(self, painter, option, index): # 自定义绘制富文本内容 html_content = index.data(Qt.DisplayRole) or "" doc = QTextDocument() doc.setHtml(html_content) # 调整文档大小以适配单元格 doc.setTextWidth(option.rect.width()) painter.save() # 设置绘制区域,避免内容超出单元格 painter.translate(option.rect.topLeft()) doc.drawContents(painter) painter.restore() # 绘制单元格选中状态的边框(保留默认选中样式) if option.state & QStyle.State_Selected: painter.save() pen = QPen(option.palette.highlight(), 1) painter.setPen(pen) painter.drawRect(option.rect.adjusted(0, 0, -1, -1)) painter.restore() class TableViewer(QMainWindow): def __init__(self): super().__init__() working_dir = os.getcwd() db_path = f"{working_dir}/temp.db" print(db_path) self.db = QSqlDatabase.addDatabase("QSQLITE") self.db.setDatabaseName(db_path) if not self.db.open(): print("数据库打开失败:", self.db.lastError().text()) sys.exit(1) self.model = QSqlTableModel(self, self.db) self.model.setTable('t1') # 设置编辑策略为手动提交(可选,根据需求调整) self.model.setEditStrategy(QSqlTableModel.OnManualSubmit) self.model.select() self.tableView = QTableView(self) self.tableView.setModel(self.model) # 调整列宽以适应内容 self.tableView.resizeColumnsToContents() # 设置行高以显示多行富文本 self.tableView.verticalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) # 为第3列(Full Name)设置富文本委托 self.tableView.setItemDelegateForColumn(3, RichTextDelegate()) # 添加工具栏(可选,用于格式设置按钮) toolbar = self.addToolBar("格式工具") bold_btn = QAction(QIcon(), "加粗", self) bold_btn.setShortcut("Ctrl+B") bold_btn.triggered.connect(lambda: self.apply_format_to_current_editor(QTextCharFormat.FontWeight, QFont.Bold)) toolbar.addAction(bold_btn) italic_btn = QAction(QIcon(), "斜体", self) italic_btn.setShortcut("Ctrl+I") italic_btn.triggered.connect(lambda: self.apply_format_to_current_editor(QTextCharFormat.FontItalic, True)) toolbar.addAction(italic_btn) underline_btn = QAction(QIcon(), "下划线", self) underline_btn.setShortcut("Ctrl+U") underline_btn.triggered.connect(lambda: self.apply_format_to_current_editor(QTextCharFormat.UnderlineStyle, QTextCharFormat.SingleUnderline)) toolbar.addAction(underline_btn) layout = QVBoxLayout() layout.addWidget(self.tableView) widget = QWidget() widget.setLayout(layout) self.setCentralWidget(widget) self.setWindowTitle("QTableView富文本编辑器") self.resize(800, 400) self.show() def apply_format_to_current_editor(self, format_property, target_value): # 获取当前正在编辑的单元格编辑器 index = self.tableView.currentIndex() if index.column() != 3: return editor = self.tableView.indexWidget(index) if isinstance(editor, QTextEdit): delegate = self.tableView.itemDelegateForColumn(3) delegate.toggle_format(editor, format_property, target_value) if __name__ == '__main__': app = QApplication(sys.argv) tv = TableViewer() sys.exit(app.exec_())
关键实现说明
1. 富文本数据存储
- 将单元格内容以HTML格式存入SQLite数据库,数据库的TEXT类型可直接存储HTML字符串,确保富文本样式信息不会丢失。
- 首次初始化数据库时,插入的示例数据已包含HTML标签,用于测试渲染效果。
2. 委托核心修改
- createEditor:创建QTextEdit编辑器并绑定快捷键,实现选中文本的格式切换。
- setEditorData/setModelData:替换原纯文本逻辑,改为加载和保存HTML内容,确保富文本数据在编辑和存储间正确流转。
- paint方法:不再依赖默认的纯文本绘制,而是使用QTextDocument解析HTML并绘制到单元格,同时保留选中状态的边框绘制,保证视觉一致性。
3. 格式操作逻辑
toggle_format方法实现格式切换:检测选中文本的当前格式,若已设置则取消,否则应用目标格式(如Ctrl+B在加粗和正常之间切换)。- 工具栏按钮与快捷键功能一致,方便鼠标操作。
4. 单元格适配
- 开启行高自动调整(
ResizeToContents),确保多行富文本内容能完整显示。 - QTextDocument设置文本宽度为单元格宽度,避免内容超出单元格边界。
内容的提问来源于stack exchange,提问作者Badri
相关产品推荐
相关产品推荐

