python - 值更改后使用代理模型更改 QTableView 单元格的背景颜色

标签 python pyqt pyqt5 qsortfilterproxymodel

我有一个子类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 单元格背景颜色的答案建议更改数据方法 How to change cell's background color of a QTableView [duplicate] 但这会在开始时给单元格着色

我在QT论坛中找到了一种在 View 和模型之间插入代理模型的方法 How to simply change the background color of a cell inside a 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_())

最佳答案

如果您想使用代理来更改颜色,则只需重写 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)
# ...

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

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)
# ...

关于python - 值更改后使用代理模型更改 QTableView 单元格的背景颜色,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62060843/

相关文章:

python - 让工作线程在 GUI 线程中等待用户输入? Python/PyQt

python - 从 PyQt5 迁移到 PySide2 时的 QVariant 替代方案

python - 选项卡中的小部件放置

python - 为 QListWidget 中的特定项目设置不同的颜色

python - 在 Python3.6.1 中调用 loop.close asyncio.get_event_loop 后无法创建新的事件循环

python - 在 flask 中创建 query_string 时出错

python - 将数学应用于 python 中的列表成员

python - 从 pandas df 更新数据库中的现有行

python - 如何使用 QAbstractTableModel 控制 QTableView 的 Header

python - 在 windows 8 上安装 spyder python