Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python emit signal on clicked QTreeview item checkbox changed

How can I emit a signal when the checkbox of a treeview item is changed?

import sys
from PySide import QtGui, QtCore

class Browser(QtGui.QDialog):
    def __init__(self, parent=None):
        super(Browser, self).__init__(parent)

        self.initUI()

    def initUI(self):
        self.resize(200, 300)
        self.setWindowTitle('Assets')
        self.setModal(True)

        self.results = ""

        self.uiItems = QtGui.QTreeView()
        self.uiItems.setAlternatingRowColors(True)
        self.uiItems.setSortingEnabled(True)
        self.uiItems.sortByColumn(0, QtCore.Qt.AscendingOrder)
        self.uiItems.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
        self.uiItems.header().setResizeMode(QtGui.QHeaderView.ResizeToContents)

        grid = QtGui.QGridLayout()
        grid.setContentsMargins(0, 0, 0, 0)
        grid.addWidget(self.uiItems, 0, 0)
        self.setLayout(grid)

        self.show()
        self.create_model()

    def create_model(self):
        items = [
            'Cookie dough',
            'Hummus',
            'Spaghetti',
            'Dal makhani',
            'Chocolate whipped cream'
        ]

        model = QtGui.QStandardItemModel()
        model.setHorizontalHeaderLabels(['Name'])

        for item in items:
            model.insertRow(0)

            # Append object
            model.setData(model.index(0, 0), QtCore.Qt.Unchecked, role = QtCore.Qt.CheckStateRole)
            model.setData(model.index(0, 0), item)

            item = model.itemFromIndex(model.index(0,0))
            item.setCheckable(True)


        self.uiItems.setModel(model)


def main():
    app = QtGui.QApplication(sys.argv)
    ex = Browser()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()
like image 442
JokerMartini Avatar asked Oct 14 '25 04:10

JokerMartini


1 Answers

A major problem with using the itemChanged signal is that it doesn't tell you what changed. It would be so much more useful if it sent the specific role of the data that had changed.

As it is, there is always a danger of getting false positives from changes to other types of data that you are not interested in (there are fifteen pre-defined data roles, and any number of user-defined ones).

So a more robust solution would be to sub-class the model and emit a custom signal that specifically includes the role:

        model = StandardItemModel()
        ...

        self.uiItems.setModel(model)
        model.itemDataChanged.connect(self.handleItemDataChanged)

    def handleItemDataChanged(self, item, role):
        if role == QtCore.Qt.CheckStateRole:
            print(item.text(), item.checkState())


class StandardItemModel(QtGui.QStandardItemModel):
    itemDataChanged = QtCore.Signal(object, object)

    def setData(self, index, value, role=QtCore.Qt.EditRole):
        oldvalue = index.data(role)
        result = super(StandardItemModel, self).setData(index, value, role)
        if result and value != oldvalue:
            self.itemDataChanged.emit(self.itemFromIndex(index), role)
        return result
like image 80
ekhumoro Avatar answered Oct 16 '25 17:10

ekhumoro



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!