Python发出信号当QTreeView项目复选框更改时。

4
当树视图项的复选框更改时,如何发出信号?
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()
2个回答

4
使用 itemChanged 信号的一个主要问题是它并没有告诉你发生了什么变化。如果该信号发送了已更改数据的特定 角色,那么它将更加有用。
事实上,总会存在因多种数据类型更改导致您不感兴趣的错误结果(有十五个预定义数据角色和任意数量的用户定义角色)。
因此,更健壮的解决方案是对模型进行子类化,并发出包含角色的自定义信号:
        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

1
使用QStandardItemModel中的itemChanged信号。
import sys
from PyQt4 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)

        # Added the following line.
        model.itemChanged.connect(self.test)
        self.uiItems.setModel(model)

    # Added the following method.
    def test(self, item):
        if item.text() == "Hummus":
            if item.checkState() == QtCore.Qt.Checked:
                # Hummus is selected
                # do something here
                pass
            else:
                # Hummus is deselected
                # do something here
                pass
        if item.text() == "Spaghetti":
            if item.checkState() == QtCore.Qt.Checked:
                # Spaghetti is selected
                # do something here
                pass
            else:
                # Spaghetti is deselected
                # do something here
                pass


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


if __name__ == '__main__':
    main()

我遇到了一个问题。我有一个QTreeWidget,用QTreeWidgetItems填充,然后将其他QTreeWidgetItems作为子项。当所有子项的复选框都关闭时,它会自动取消选中父项。但是,这不会发出信号。因此,我能够捕获子部件本身的更改,但是当我查询父状态时,它尚未取消选中,因为似乎在传递信号之后才发生这种情况。您知道如何捕获这个吗? - Jesse
当然,在发布这篇文章后,我意识到我想要查看父级是否处于选中或未选中状态。但显然,我错过了第三个“部分选中”的选项。将其包括在可能的状态中似乎可以解决我的问题。 - Jesse

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接