PySide6 Highlight a row in qtableview based on cell values

I am trying to highlight a whole row red based to two cell values in that same row. See my code below.

It is kind of weird behavior. The cell will turn red but not the whole row. Or the whole row will turn red except for the single cell positioned furthest right. During this weird state, I can move the whole window a little bit and then the whole row highlights like I want.

Operating system is RHEL 8

def data(self, index, role):
    if role == Qt.DisplayRole:
        return self._data[index.row()][index.column()]
    elif role == Qt.ItemDataRole.BackgroundRole:
        val1 = self._data[index.row()][2]
        val2 = self._data[index.row()][5]
        if val1 != val2:
            return QtGui.QBrush(Qt.red)
        else:
            return QtGui.QBrush(Qt.white)
    return None

Hello @webbsb,

This is probably related to setData, where you should indicate the whole row has changed if you want it to be updated correctly, by asking Qt API to reevaluate all items of the row, and not only the one which has changed

Here is a simple code example:

import PySide6.QtCore as qc
import PySide6.QtGui as qg
import PySide6.QtWidgets as qw


class DataModel(qc.QAbstractTableModel):
    def __init__(self, data):
        super().__init__()
        self._data = data

    def rowCount(self, parent):
        return len(self._data)

    def columnCount(self, parent):
        return len(self._data[0])

    def data(self, index, role):
        if role == qc.Qt.ItemDataRole.DisplayRole:
            return self._data[index.row()][index.column()]
        elif role == qc.Qt.ItemDataRole.BackgroundRole:
            val1 = int(self._data[index.row()][2])
            val2 = int(self._data[index.row()][4])
            if val1 != val2:
                return qg.QBrush(qc.Qt.GlobalColor.darkRed)
            else:
                return qg.QBrush(qc.Qt.GlobalColor.darkBlue)

        return None

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

    def setData(self, index, value, role):
        if role == qc.Qt.ItemDataRole.EditRole:
            self._data[index.row()][index.column()] = value
            changed_idxs = (self.index(index.row(), 0), self.index(index.row(), 4))
            self.dataChanged.emit(*changed_idxs)
            return True
        return False

if __name__ == '__main__':
    app = qw.QApplication.instance() or qw.QApplication([])
    view = qw.QTableView()
    model = DataModel([
        [0, 1, 2, 3, 4],
        [2, 2, 2, 2, 2],
        [3, 3, 3, 3, 3],
        [4, 4, 4, 4, 4],
        [5, 5, 5, 5, 5],
        [6, 6, 6, 6, 6],
        [1, 2, 3, 4, 5],
        [6, 7, 8, 9, 10],
    ])
    view.setModel(model)

    qc.QTimer.singleShot(1000, lambda: model.setData(model.index(0, 2), 4, qc.Qt.ItemDataRole.EditRole))
    qc.QTimer.singleShot(2000, lambda: model.setData(model.index(1, 2), 4, qc.Qt.ItemDataRole.EditRole))
    qc.QTimer.singleShot(3000, lambda: model.setData(model.index(6, 2), 5, qc.Qt.ItemDataRole.EditRole))

    view.show()
    app.exec()
1 Like