nochenon
nochenon

Reputation: 346

QPaint crashed in subclassed QStyledItemDelegate

I subclassed a QStyledItemDelegate to change the highlight color of the selections, and if there is a QColor in ForegroundRole and BackgroundRole I will try to blend two colors.

However, when I'm trying to select a row in the tableview, following error message shows up:

TypeError: arguments did not match any overloaded call:
  setColor(self, QPalette.ColorGroup, QPalette.ColorRole, Union[QColor, Qt.GlobalColor, QGradient]): argument 1 has unexpected type 'ColorRole'
  setColor(self, QPalette.ColorRole, Union[QColor, Qt.GlobalColor, QGradient]): argument 2 has unexpected type 'NoneType'

and terminal shows:

QPainter::begin: A paint device can only be painted by one painter at a time.
QPainter::setCompositionMode: Painter not active
QBackingStore::endPaint() called with active painter; did you forget to destroy it or call QPainter::end() on it?

Here is my implementation:

class StyleDelegateForTable_List(QStyledItemDelegate):
    """
    Customize highlight style for ListView & TableView
    """
    
    def __init__(self, parent):
        super().__init__(parent)
        self.hightColor = QtGui.QColor("#0096ff")

    def paint(self, painter, option: QtWidgets.QStyleOptionViewItem, index):
        self.initStyleOption(option, index)
        if (option.state & QtWidgets.QStyle.StateFlag.State_Selected and 
            option.state & QtWidgets.QStyle.StateFlag.State_Active):
            # get foreground color, 
            # don't know where to set foreground color though...
            fg = self.getColor(index, isBG = False)
            # get background color
            bg = self.getColor(index, isBG = True)
            # set highlight color
            option.palette.setColor(QtGui.QPalette.ColorRole.Highlight, 
                                    self.mixColors(bg))
        QStyledItemDelegate.paint(self, painter, option, index)

    def getColor(self, index: QModelIndex, isBG = True) -> QtGui.QColor:
        parentWidget = self.parent()
        model = parentWidget.model()
        dataRole = Qt.ItemDataRole.BackgroundRole if isBG else Qt.ItemDataRole.ForegroundRole
        
        # TableView
        if isinstance(parentWidget, QtWidgets.QTableView):
            if isinstance(model, QSortFilterProxyModel):
                # proxy model
                sourceIndex = model.mapToSource(index)
                return model.sourceModel().data(sourceIndex, dataRole)
            
            elif isinstance(model, TestDataTableModel):
                # abstract table model
                return model.data(index, dataRole)                

        # ListView
        if isinstance(parentWidget, QtWidgets.QListView):
            if isinstance(model, QSortFilterProxyModel):
                # all of listView uses proxyModel
                sourceIndex = model.mapToSource(index)
                return model.sourceModel().data(sourceIndex, dataRole)
        
        return QtGui.QColor("#000000")
        
    def mixColors(self, src) -> QtGui.QColor:
        if isinstance(src, QtGui.QColor):
            r = int(src.red()*0.7   + self.hightColor.red()*0.3)
            g = int(src.green()*0.7 + self.hightColor.green()*0.3)
            b = int(src.blue()*0.7  + self.hightColor.blue()*0.3)
            return QtGui.QColor(r, g, b)
        else:
            # I intended to mix default bg or fg color 
            # with highlight color but default is None.
            # return hightlight color for now
            self.hightColor

I tried to set a breakpoint in getColor, but my app just crashed, what did I do wrong here?


Edit: This question is invalid, as @ musicamante points out, mixColors returns None instead of hightlight color if the original Background/Foreground is None.

I will keep this question in case someone needs the same functionality.

Upvotes: 0

Views: 93

Answers (0)

Related Questions