I have a QStandardItemModel being displayed in two QTreeViews. The first TreeView uses the standard QStyledItemDelegate without any alterations and shows the items with a checkbox, an icon and their display text. The second view is supposed to show the same tree, although a custom implementation of QStyledItemDelegate is supposed to do the following:
Whether items are in italics/not clickable or not and whether they're displayed in red or not is saved in a custom DataRole and accessed using index.data(custom_role).
My problem is: I can't get text to be shown in red and I have no idea how to remove the checkbox, or how to make items selectable or not.
Here's what I have:
class PostProcessedDelegate(QtWidgets.QStyledItemDelegate):
def __init__(self):
super().__init__()
def paint(self, painter, option, index):
custom_option = QtWidgets.QStyleOptionViewItem(option)
custom_painter = painter
if not index.data(Item.IS_PROCESSED):
custom_option.font.setItalic(True)
#ALSO MAKE ITEM NON-SELECTABLE HERE
if index.data(Item.HAS_PROCESSING_ERROR):
custom_painter.setPen(QtGui.QColor(255,0,0)) #THIS DOESNT HAVE ANY EFFECT
#REMOVE CHECKBOX BEFORE PAINTING
super().paint(custom_painter, custom_option, index)
This screenshot shows the first TreeView to the left (the one without any alterations) and the second to the right, with only some of the required changes in effect.
It is not necessary to override the paint method but to modify the QStyleOptionViewItem in initStyleOption, for selection you must override the selectionCommand method of the QTreeView:
from enum import IntEnum, auto
import random
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class Item(IntEnum):
IS_PROCESSED = QtCore.Qt.UserRole
HAS_PROCESSING_ERROR = auto()
def create_icon():
color = QtGui.QColor(*random.sample(range(255), 3))
pixmap = QtGui.QPixmap(128, 128)
pixmap.fill(color)
return QtGui.QIcon(pixmap)
class StyledItemDelegate(QtWidgets.QStyledItemDelegate):
def initStyleOption(self, option, index):
super().initStyleOption(option, index)
if not index.data(Item.IS_PROCESSED):
option.font.setItalic(True)
if index.data(Item.HAS_PROCESSING_ERROR):
option.palette.setBrush(QtGui.QPalette.Text, QtGui.QColor(255, 0, 0))
option.features &= ~QtWidgets.QStyleOptionViewItem.HasCheckIndicator
class TreeView(QtWidgets.QTreeView):
def __init__(self, parent=None):
super().__init__(parent)
delegate = StyledItemDelegate(self)
self.setItemDelegate(delegate)
def selectionCommand(self, index, event):
if not index.data(Item.IS_PROCESSED):
return QtCore.QItemSelectionModel.NoUpdate
return super().selectionCommand(index, event)
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
model = QtGui.QStandardItemModel(self)
left_view = QtWidgets.QTreeView()
right_view = TreeView()
lay = QtWidgets.QHBoxLayout(self)
lay.addWidget(left_view)
lay.addWidget(right_view)
left_view.setModel(model)
right_view.setModel(model)
root_item = QtGui.QStandardItem("Root")
model.appendRow(root_item)
self.populate(root_item, 3)
left_view.expandAll()
right_view.expandAll()
def populate(self, root_item, level):
for i in range(random.randint(2, 4)):
it = QtGui.QStandardItem("item {}".format(i))
it.setIcon(create_icon())
it.setCheckable(True)
it.setData(random.choice([True, False]), Item.IS_PROCESSED)
it.setData(random.choice([True, False]), Item.HAS_PROCESSING_ERROR)
root_item.appendRow(it)
next_level = level - 1
if next_level > 0:
self.populate(it, next_level)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())