使用 PySide2 在 QTableView 中设置文本样式

Posted

技术标签:

【中文标题】使用 PySide2 在 QTableView 中设置文本样式【英文标题】:Text styling in QTableView with PySide2 【发布时间】:2019-01-18 23:41:20 【问题描述】:

我有一个填充了适当模型的 QTableView。 我想根据上下文更改文本的样式:

文本,如果括号之间有什么东西,只是这部分文本应该变成绿色-包括括号-(和粗体,只要不是更难)。

如果你能提供一个sn-p或超级简单的例子,我很感激。

【问题讨论】:

据我了解,您希望括号中的文本加上括号变为绿色或粗体,其余的保持不变,对吗? 是的,正是,谢谢!!绿色,或绿色和粗体,但不仅仅是粗体。 所以,直接回答你的问题,不要绕太多圈 @eyllanesc,现在这很简单直接,你能帮帮我吗? 【参考方案1】:

你必须使用一个使用QTextDocument的委托:

import random
from PySide2 import QtCore, QtGui, QtWidgets

words = '''Lorem ipsum dolor sit amet, consectetur adipiscing elit. 
Mauris euismod cursus mi sit amet pellentesque. 
Proin sed lectus sed augue scelerisque congue eget quis leo. 
Curabitur ultrices nisi nisi, placerat gravida urna sagittis et. 
Nullam vitae urna tortor. Curabitur a lobortis metus, et laoreet arcu. 
Quisque a mi in purus molestie porta non sit amet purus. 
Sed porta non purus et suscipit.'''.split()

class HighlightDelegate(QtWidgets.QStyledItemDelegate):
    def __init__(self, parent=None):
        super(HighlightDelegate, self).__init__(parent)
        self.doc = QtGui.QTextDocument(self)
        self._regex = QtCore.QRegularExpression()
        self._highlight_format = QtGui.QTextCharFormat()

    def paint(self, painter, option, index):
        painter.save()
        options = QtWidgets.QStyleOptionViewItem(option)
        self.initStyleOption(options, index)
        self.doc.setPlainText(options.text)
        self.apply_highlight()
        options.text = ""
        style = QtWidgets.QApplication.style() if options.widget is None \
            else options.widget.style()
        style.drawControl(QtWidgets.QStyle.CE_ItemViewItem, options, painter)

        ctx = QtGui.QAbstractTextDocumentLayout.PaintContext()
        if option.state & QtWidgets.QStyle.State_Selected:
            ctx.palette.setColor(QtGui.QPalette.Text, option.palette.color(
                QtGui.QPalette.Active, QtGui.QPalette.HighlightedText))
        else:
            ctx.palette.setColor(QtGui.QPalette.Text, option.palette.color(
                QtGui.QPalette.Active, QtGui.QPalette.Text))

        textRect = style.subElementRect(
            QtWidgets.QStyle.SE_ItemViewItemText, options)

        if index.column() != 0:
            textRect.adjust(5, 0, 0, 0)

        the_constant = 4
        margin = (option.rect.height() - options.fontMetrics.height()) // 2
        margin = margin - the_constant
        textRect.setTop(textRect.top() + margin)

        painter.translate(textRect.topLeft())
        painter.setClipRect(textRect.translated(-textRect.topLeft()))
        self.doc.documentLayout().draw(painter, ctx)

        painter.restore()

    def apply_highlight(self):
        cursor = QtGui.QTextCursor(self.doc)
        cursor.beginEditBlock()
        highlightCursor = QtGui.QTextCursor(self.doc)
        while not highlightCursor.isNull() and not highlightCursor.atEnd():
            highlightCursor = self.doc.find(self.regex, highlightCursor)
            if not highlightCursor.isNull():
                highlightCursor.mergeCharFormat(self.highlightFormat)
        cursor.endEditBlock()

    @property
    def regex(self):
        return self._regex

    @regex.setter
    def regex(self, regex):
        if self._regex == regex: return
        self._regex = regex

    @property
    def highlightFormat(self):
        return self._highlight_format

    @highlightFormat.setter
    def highlightFormat(self, fmt):
        self._highlight_format = fmt

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)

        self.table = QtWidgets.QTableView()

        self._delegate = HighlightDelegate(self.table)
        self._delegate.regex = QtCore.QRegularExpression(r"\(.*?\)")
        fmt = QtGui.QTextCharFormat()
        fmt.setForeground(QtCore.Qt.green)
        fmt.setFontWeight(QtGui.QFont.Bold)
        self._delegate.highlightFormat = fmt
        self.table.setItemDelegate(self._delegate)

        model = QtGui.QStandardItemModel(10, 4)
        for i in range(model.rowCount()):
            for j in range(model.columnCount()):
                item = QtGui.QStandardItem("()".format(*random.sample(words,3)))
                model.setItem(i, j, item)
        self.table.setModel(model)
        self.setCentralWidget(self.table)

if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())

【讨论】:

@eyllanesc ...我正在尝试将您的示例转换为 pyqt4 ...任何帮助将不胜感激。 :) @panofish python2 还是 python3? @eyllanesc .. python2... 我还更新了您尝试转换 https://***.com/a/57064002/259538 的其他示例 @panofish 我已经添加了 PyQt4 的版本,稍后我也会为这个答案添加一个类似的版本。 @eyllanesc .. 你是我的英雄。 PyQt4 版本很好用!

以上是关于使用 PySide2 在 QTableView 中设置文本样式的主要内容,如果未能解决你的问题,请参考以下文章

使用 PySide2 在 QTableView 中设置文本样式

使用 PySide2 和 QTableView 如何使用 pandas 模型在表格视图中获得多个委托?

QTableView 在 PyQt5/PySide2 中的每个选择上加载数据时锁定主窗体 [重复]

PySide2 QListView QTableView 同步问题

为上一个问题 PySide2 QListView 和 QTableView 添加功能

上一个问题 PySide2 QListView 和 QTableView 的新功能