Search code examples
pythonpyqtpyqt4qtableview

PyQt4 QTableView cell text changes color on row selection


I'm developing a small application that compares *.xls and *.xlsx files using PyQt4.

Here is what the comparison window looks like. The row is highlighted in light red, while the cell text has a bright red color.

enter image description here

When I select the row by clicking on it all the red highlighting is gone.

enter image description here

Is there any way, in this situation, to make the cells that are marked with red to stay that way ?

I'm using QtCore.QAbstractTableModel for each QtGui.QTableView

def data(self, index, role):

    """
    Updating tableView data

    """

    #########################################################
    #            Data role -> Updating cell contents        #  
    #########################################################  

    if role == QtCore.Qt.DisplayRole:
        row = index.row()
        if 0 <= row < self.rowCount():
            column = index.column()
            if 0 <= column < self.columnCount():
                return self._data[row][column]

    #########################################################
    #          Background role -> Updating row color        #  
    ######################################################### 

    if role ==  QtCore.Qt.BackgroundRole and index.row() in self._marked_rows:
        customColor = QtGui.QColor(255, 204, 204)
        return QtCore.QVariant(QtGui.QBrush(customColor))  

    #########################################################
    #     TextColorRole role -> Updating cell text color    #
    ######################################################### 

    if role == QtCore.Qt.ForegroundRole:
        if str(index.row()) + ':' + str(index.column()) in self._marked_cells:
            return QtCore.QVariant(QtGui.QColor(QtCore.Qt.red))

After some searches I tried using QtGui.QStyledItemDelegate. Now the text keeps its color, but there is no highlighting and I do not know how to keep the row's light red color.

enter image description here

class TextColorDelegate(QtGui.QStyledItemDelegate):

    def __init__(self, cells, parent = None):

        QtGui.QStyledItemDelegate.__init__(self, parent)
        self.cells = cells

    def paint(self, painter, option, index):

       painter.save()

       value = index.data(QtCore.Qt.DisplayRole)
       if value.isValid():
           text = value.toString()

           if str(index.row()) + ':' + str(index.column()) in self.cells:
               painter.setPen(QtGui.QPen(QtCore.Qt.red))
               painter.drawText(option.rect, QtCore.Qt.AlignVCenter, text)
           else:
               painter.setPen(QtGui.QPen(QtCore.Qt.black))
               painter.drawText(option.rect, QtCore.Qt.AlignVCenter, text)

       painter.restore()

self.model_1 = TableModel(_data_1, 
                         columns_string, 
                         _markedRows_1, 
                         _markedCells_1, 
                         self.appPath, 
                         self.tableView_1)

delegate_1 = TextColorDelegate(_markedCells_1, self)
self.tableView_1.setModel(self.model_1)
self.tableView_1.setItemDelegate(delegate_1)

Is there any way to target those specific cells and keep the row highlighting ?


Solution

  • I managed to find a solution on my own. Maybe a more simple one is possible, but it works.

    class TextColorDelegate(QtGui.QStyledItemDelegate):
    
        """
        Delegate used for changing text color and highlighting behaviour  
    
        """ 
    
        def __init__(self, cells, parent = None):
    
            """
            Object initialization
    
            cells - marked cells that have different content
    
            """
    
            QtGui.QStyledItemDelegate.__init__(self, parent)
            self.cells = cells
    
        def paint(self, painter, option, index):
    
            """
            Painter function used for overriding display behaviour
    
            """
    
            painter.save()
    
            displayText    = index.data(QtCore.Qt.DisplayRole)
            backgroudColor = index.data(QtCore.Qt.BackgroundColorRole)
    
            customColor    = QtGui.QColor(255, 204, 204)
            blackColor     = QtCore.Qt.black
            yellowColor    = QtCore.Qt.yellow 
            redColor       = QtCore.Qt.red
    
            backgroundFlag = backgroudColor.isValid()
            textFlag       = displayText.isValid()
            textContent    = displayText.toString()
    
            if backgroudColor.isValid():
    
                ###################################################################
                #               Evaluating rows with differences                  #
                #   Adjusting background and text color depending on QStyleState  #
                ###################################################################
    
                painter.fillRect(option.rect, customColor)   #set row background color 
    
                if (option.state & QtGui.QStyle.State_Selected):
                    painter.fillRect(option.rect, option.palette.highlight())       
                    color_to_set = yellowColor if ( str( index.row() ) + ':' + str( index.column() ) ) in self.cells else blackColor                                              
                else:
                    color_to_set = redColor if ( str( index.row() ) + ':' + str( index.column() ) ) in self.cells else blackColor
    
                ###################################################################
                #               Evaluating rows with no differences               #
                #   Adjusting background and text color depending on QStyleState  #
                ###################################################################
    
            else:
                if (option.state & QtGui.QStyle.State_Selected) : painter.fillRect(option.rect, option.palette.highlight()) 
                color_to_set = blackColor
    
    
            if textFlag:                                                     
                painter.setPen(QtGui.QPen(color_to_set))
                painter.drawText(option.rect, QtCore.Qt.AlignVCenter, textContent)
    
            painter.restore()
    

    Now the highlighting works.

    https://i.sstatic.net/9r4gq.jpg
    https://i.sstatic.net/Nruvr.jpg