首页 > 解决方案 > 更改值后使用代理模型更改 QTableView 的单元格的背景颜色

问题描述

我有一个子类QAbstractTableModel

其中包含 None 类型值以将行显示为空

class ViewModel(qtc.QAbstractTableModel):

    def __init__(self, input_data=None):
        super().__init__()

        self.input_data = input_data or [[None, None],[None, None]]

如果插入的值(替换无类型值)在/超出某个范围,我想更改单元格的颜色

z = 12 <= x <= 20

# False == red, True == green

self.model.layoutChanged.emit()仅当项目被编辑或被执行时,颜色才会改变

更改 QTableView 的单元格背景颜色的答案建议更改数据方法如何更改 QTableView 的单元格背景颜色 [重复] 但这将在开始时为单元格着色

我在 QT 论坛中找到了一种在视图和模型之间插入代理模型的方法 如何简单地更改 TableView 内单元格的背景颜色

我正在尝试将代码实现到 Pyqt5 中,到目前为止没有成功。是否有我不知道的 PyQt5 方法?

示例代码

import sys
import re

from PyQt5 import QtWidgets as qtw
from PyQt5 import QtCore as qtc


class ViewModel(qtc.QAbstractTableModel):

    def __init__(self, input_data=None):
        super().__init__()

        self.input_data = input_data or [[None, None],[None, None]]



    def data(self, index, role):  # parameter index, role are needed !
        if role == qtc.Qt.DisplayRole:
            try:
                text = self.input_data[index.row()][index.column()]
            except IndexError:
                text = None

            return text

    def rowCount(self, index=qtc.QModelIndex()):
        return 0 if index.isValid() else len(self.input_data)


    def columnCount(self, index):
        return len(self.input_data[0])

    def headerData(self, section, orientation, role):
        # section is which index of the orientation
        if role == qtc.Qt.DisplayRole:
            if orientation == qtc.Qt.Vertical:
                return "row"

    def flags(self, index):
        return qtc.Qt.ItemIsEditable | qtc.Qt.ItemIsSelectable | qtc.Qt.ItemIsEnabled

    def setData(self, index, value, role=qtc.Qt.EditRole):
        if role == qtc.Qt.EditRole:
            try:
                row = index.row()
                column = index.column()

                pattern = '^[\d]+(?:,[\d]+)?$'


                if re.fullmatch(pattern, value, flags=0):
                    print("true")
                    self.input_data[row][column] = value  # float
                else:
                    print("nope")
                    pass

                return True

            except ValueError:
                print("not a number")
                return False


class MainWindow(qtw.QWidget):



    def __init__(self):
        super().__init__()

        # View
        table_view = qtw.QTableView()

        self.model = ViewModel()

        table_view.setModel(self.model)

        # size and position
        qtRectangle = self.frameGeometry()
        centerPoint = qtw.QDesktopWidget().availableGeometry().center()
        qtRectangle.moveCenter(centerPoint)
        self.move(qtRectangle.topLeft())
        # size
        self.resize(1000, 410)

        # layout
        qvboxlayout = qtw.QVBoxLayout()
        qvboxlayout.addWidget(table_view)

        self.setLayout(qvboxlayout)
        self.show()


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

标签: pythonpyqtpyqt5qsortfilterproxymodel

解决方案


如果你想使用代理来改变颜色,那么只有data()方法应该被覆盖:

class ColorProxy(qtc.QIdentityProxyModel):
    def data(self, index, role=qtc.Qt.DisplayRole):
        if role == qtc.Qt.BackgroundRole:
            data = index.data()
            try:
                value = float(data)
            except (ValueError, TypeError) as e:
                print("error:", e)
            else:
                return qtg.QColor("green") if 12 <= value <= 20 else qtg.QColor("red")
        return super().data(index, role)
# ...
self.model = ViewModel()

proxy = ColorProxy()
proxy.setSourceModel(self.model)

table_view.setModel(proxy)
# ...

另一种解决方案是使用委托

class ColorDelegate(qtw.QStyledItemDelegate):
    def initStyleOption(self, option, index):
        super().initStyleOption(option, index)
        data = index.data()
        try:
            value = float(data)
        except (ValueError, TypeError) as e:
            print("error:", e)
        else:
            color = qtg.QColor("green") if 12 <= value <= 20 else qtg.QColor("red")
            option.backgroundBrush = color
# ...
table_view = qtw.QTableView()

self.model = ViewModel()

delegate = ColorDelegate(table_view)
table_view.setItemDelegate(delegate)

table_view.setModel(self.model)
# ...

推荐阅读