Don Smythe
Don Smythe

Reputation: 9814

setStyleSheet or QStyledItemDelegate for a node in QTreeView

I am trying to change a icon for specific nodes in a QTreeView. Nodes will use QCheckbox, and based on app logic, some nodes will instead use other icons for node selected/unselected state.

An example below shows how I can set a stylesheet for the entire tree, but I don't think I can set a stylesheet for a single node in the tree.

#Based on http://stackoverflow.com/questions/5374168/unable-to-select-checkbox-inside-treeview
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4 import QtGui, QtCore

class Window(QtGui.QWidget):
    changeStyleTriggered = QtCore.pyqtSignal()

    def __init__(self):
        QtGui.QWidget.__init__(self)
        self.createTree()
        self.connectSlots()

    def createTree(self):
        data = ['A', 'B', 'C', 'D', 'E', 'F']
        model = MyTreeView(data)
        self.treeView = QTreeView()
        self.treeView.setModel(model)
        layout = QtGui.QVBoxLayout()
        layout.addWidget(self.treeView)
        self.changeIconPushButton = QtGui.QPushButton("Change a single icon")
        layout.addWidget(self.changeIconPushButton)
        self.setLayout(layout)

    def fireChangeStyleSignal(self):
        self.changeStyleTriggered.emit()

    @pyqtSlot()
    def changeStyleSignal(self):
        print(">>changeStyleSignal()")
        self.setStyleSheet("QTreeView::indicator:unchecked {image: url(:/icons/image.png);}")

    def connectSlots(self):
        self.changeStyleTriggered.connect(self.changeStyleSignal)
        self.changeIconPushButton.clicked.connect(self.fireChangeStyleSignal)

class TestItem():
    def __init__(self, name, checked):
        self.checked = checked
        self.name = name

class MyTreeView(QAbstractListModel):
    def __init__(self, args, parent=None):
        super(StbTreeView, self).__init__(parent)

        self.args = []
        for item_name in args:
            self.args.append(TestItem(item_name, False))

        for item in self.args:
            print (item.name)

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

    def headerData(self, section, orientation, role):
        if role == Qt.DisplayRole:
            if orientation == Qt.Horizontal:
                return "Nodes"

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

    def data(self, index, role=Qt.DisplayRole):
        if role == Qt.DisplayRole:
            row = index.row()
            print (self.args[row].name)
            return self.args[row].name

        if role == Qt.CheckStateRole:
            row = index.row()
            print (self.args[row].checked)
            if self.args[row].checked == False:
                return Qt.Unchecked
            else:
                return Qt.Checked

    def setData(self, index, value, role):
        if role == Qt.CheckStateRole:
            row = index.row()
            self.args[row].checked = not self.args[row].checked             
        return True

def main():
    myapp = QApplication(sys.argv)

    window = Window()
    window.show()
    myapp.exec_()

if __name__ == '__main__':
    main()

The other option is to use QStyledItemDelegate. Below is a small class to change the font, but I haven't worked out how to change a single icon with delegate.

class BoldDelegate(QtGui.QStyledItemDelegate):
    def paint(self, painter, option, index):
        option.font.setWeight(QtGui.QFont.Bold)
        QtGui.QStyledItemDelegate.paint(self, painter, option, index)

and to use it run this (eg in a @pyqtSlot() for the QTreeView):

self.setItemDelegate(BoldDelegate(self))

Any ideas?

Upvotes: 0

Views: 798

Answers (1)

A QCheckBox doesn't use an icon to display its state. You should first create a project where, through whatever means, you get a widget that acts like you wish, with correct checked/unchecked appearance.

Once you have that, you'll have your delegate create such items based on some property of the data item of the model. For example, you might have a custom role that indicates to your delegate that a non-default widget class should be used to edit the item.

Upvotes: 1

Related Questions