Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Multiple selection colors in a QTreeWidget



  • I am trying to create a QTreeWidget that uses a single highlight color for all but the last selection. I been fighting this problem for 2 months now and cannot come up with a solution. I am using PySide2 in Maya 2019.

    I tried using style sheet but that is global to all selected rather than individual QTreeWidgetItems.

    Each time I am able to change the color for each selection. The window remembers the old color and creates an overlap. Once I select a different element in Maya my GUI corrects the colors.

    I tried using a delegate show in my example code. My recent attempt is overriding the drawRow but with the same results.

    from PySide2 import QtCore
    from PySide2 import QtWidgets
    from PySide2 import QtGui
    
    class TestDialog(QtWidgets.QDialog):
    
        def __init__(self):
            super(TestDialog, self).__init__()
    
            self.setWindowTitle("Test Dialog")
            self.setMinimumWidth(200)
    
            self.tree = TreeWidget()
    
            # Change all the highlighted items to the same color
            # palette = QtGui.QPalette()
            # palette.setColor(QtGui.QPalette.Highlight, QtGui.QColor(93, 93, 93))
            # self.tree.setPalette(palette)
    
            main_layout = QtWidgets.QVBoxLayout(self)
            main_layout.addWidget(self.tree)
    
            colors = ['red', 'green', 'blue', 'purple', 'black']
            parent = self.tree
            for color in colors:
                parent = TreeWidgetItem(parent, color)
    
            self.tree.expandAll()
    
    class TreeWidget(QtWidgets.QTreeWidget):
        def __init__(self):
            super(TreeWidget, self).__init__()
            self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
            self.setIndentation(10)
            self.setColumnCount(2)
            self.header().resizeSection(1, 28)
            self.header().swapSections(1, 0)
            self.setHeaderHidden(True)
            css = """
                QTreeView::item:selected
                    {
                        background-color: grey;
                    }
                """
            # self.setStyleSheet(css)
            delegate = MyDelegate(None, self)
            self.setItemDelegate(delegate)
    
    class TreeWidgetItem(QtWidgets.QTreeWidgetItem):
        def __init__(self, parent, label):
            super(TreeWidgetItem, self).__init__(parent)
            self.setText(0, label)
    
            self.lockBox_cb = QtWidgets.QCheckBox()
    
            self.treeWidget().setItemWidget(self, 1, self.lockBox_cb)
    
    
    class MyDelegate(QtWidgets.QStyledItemDelegate):
        def __init__(self, parent, tree):
            super(MyDelegate, self).__init__(parent)
            self.tree = tree
    
        def paint(self, painter, option, index):
    
            column = index.column()
            row = index.row()
            item = self.tree.itemFromIndex(index)
            currentItem = self.tree.currentItem()
    
            brush = QtGui.QBrush(QtCore.Qt.transparent)
            painter.setBrush(brush)
            painter.fillRect(option.rect, brush)
    
            if column == 0:
                if option.state & QtWidgets.QStyle.State_Selected:
    
                    if id(currentItem) == id(item):
                        brush = QtGui.QBrush(QtGui.QColor(102, 40, 178, 255))
                    else:
                        brush = QtGui.QBrush(QtGui.QColor(226, 131, 255, 255))
                    option.palette.setBrush(QtGui.QPalette.Highlight, brush)
    
    
    
                    option_copy = QtWidgets.QStyleOptionViewItem(option)
                    option_copy.rect.setLeft(0)
                    option_copy.backgroundBrush = brush
    
                    self.tree.style().drawPrimitive(QtWidgets.QStyle.PE_PanelItemViewItem, option_copy, painter)
    
    
    
    
                super(MyDelegate, self).paint(painter, option, index)
    
    
    if __name__ == "__main__":
    
        d = TestDialog()
        d.show()
    

    The drawRow method in my main code. So, this won't work in my example:

        def drawRow(self, painter, option, index):
    
    
            item = self.itemFromIndex(index)
            currentItem = self.currentItem()
    
            if str(item.pyNode) in self.selected:
                if str(item.pyNode) == str(currentItem.pyNode):
                    brush = QtGui.QBrush(QtGui.QColor(102, 40, 178, 255))
                else:
                    brush = QtGui.QBrush(QtGui.QColor(226, 131, 255, 255))
    
                painter.fillRect(option.rect, brush)
    
            super(JointTreeWidget, self).drawRow(painter, option, index)
    
    

    Selecting the items shows both colors

    After "refreshing" the GUI by selecting a different window element in Maya. The colors fix themselves
    alt text

    Thanks


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    What version of PySide2 are you using ?
    Do you also have that if you generate that widget in a standalone application ?


Log in to reply