QStandardItem 复选框更改反映在 Pyside 中的对象上

QStandardItem checkbox changes reflected on object in Pyside

如何将 UI 中的复选框与它们所代表的属性同步?因此,当我更改 UI 中的复选框状态时,它会正确设置 class 对象上 属性 的值以匹配复选框状态?

例如,如果我点击 FumeFX_001 的继续 Sim 复选框,它也应该更改 属性 以匹配。

打印按钮可帮助测试用户单击 ui 中的复选框时是否正在更新值。

import sys
from PySide import QtGui, QtCore
import pprint

class Operation(object):
    def __init__(self, name='', script='', enabled=False):
        self.name = name
        self.script = script
        self.enabled = enabled

class FumeFX(object):
    def __init__(self, name):
        self.name = name
        self.cache = 'Z:/pipeline/max/release/test/tools/cache/####.aur'
        self.operations = [
            Operation('Sim', 'Z:/pipeline/sim.py', True),
            Operation('Continue Sim', 'Z:/pipeline/cont_sim.py', False),
            Operation('Wavelet', 'Z:/pipeline/wavelet.py', False),
            Operation('Continue Wavelet', 'Z:/pipeline/cont_wavelet.py', False),
            Operation('Post', 'Z:/pipeline/post.py', False),
            Operation('Continue Post', 'Z:/pipeline/cont_post.py', False)
        ]

class Phoenix(object):
    def __init__(self, name):
        self.name = name
        self.cache = 'Z:/pipeline/max/release/test/tools/cache/####.aur'
        self.operations = [
            Operation('Bounce', 'Z:/pipeline/sim.py', True),
            Operation('Continue Bounce', 'Z:/pipeline/cont_sim.py', False),
            Operation('Delete', 'Z:/pipeline/wavelet.py', False),
        ]

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

        self.initUI()

    def initUI(self):
        self.resize(400, 400)
        self.setWindowTitle('Assets')

        self.items_model = QtGui.QStandardItemModel()
        self.ui_items = QtGui.QTreeView()
        self.ui_items.setAlternatingRowColors(True)
        self.ui_items.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
        self.ui_items.header().setResizeMode(QtGui.QHeaderView.ResizeToContents)
        self.ui_items.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
        self.ui_items.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
        self.ui_items.setModel(self.items_model)

        self.ui_print = QtGui.QPushButton('Print')

        grid = QtGui.QVBoxLayout()
        grid.setContentsMargins(5, 5, 5, 5)
        grid.addWidget(self.ui_items)
        grid.addWidget(self.ui_print)
        self.setLayout(grid)

        self.nodes = [
            FumeFX('FumeFX_001'),
            FumeFX('FumeFX_002'),
            Phoenix('Phoenix')
        ]

        self.update_model()

        self.ui_print.clicked.connect(self.print_info)

    def print_info(self):
        for n in self.nodes:
            print n.name, n.cache
            # pprint.pprint(vars(n))
            for p in n.operations:
                pprint.pprint(vars(p))
            print '\n'

    def update_model(self):
        model = self.ui_items.model()
        model.clear()
        model.setHorizontalHeaderLabels(['Assets',''])

        # Create Data
        for x in self.nodes:
            root = []

            # Node Name
            n_main = QtGui.QStandardItem()
            n_main.setData(x.name, role=QtCore.Qt.DisplayRole)
            n_main.setData(x, role=QtCore.Qt.UserRole)
            root.append(n_main)

            # Node Output
            n_output = QtGui.QStandardItem()
            n_output.setData(x.cache, role=QtCore.Qt.DisplayRole)
            n_output.setData(x, role=QtCore.Qt.UserRole)
            root.append(n_output)

            # Operations
            for op in x.operations:
                row = []

                op_name = QtGui.QStandardItem()
                op_name.setData(op.name, role=QtCore.Qt.DisplayRole)
                op_name.setData(op, role=QtCore.Qt.UserRole)
                row.append(op_name)

                op_enabled = QtGui.QStandardItem()
                op_enabled.setData(QtCore.Qt.Checked, role=QtCore.Qt.CheckStateRole)
                op_enabled.setData(op, role=QtCore.Qt.UserRole)
                op_enabled.setCheckable(True)
                row.append(op_enabled)

                n_main.appendRow(row)

            # add node to main treeview
            model.appendRow(root)

        self.ui_items.expandAll()

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    ex = Browser()
    ex.show()
    sys.exit(app.exec_())

首先,您必须使用默认值初始化复选框:

# Operations
for op in x.operations:
    row = []
    ...
    op_enabled = QtGui.QStandardItem()
    op_enabled.setData(op, role=QtCore.Qt.UserRole)
    op_enabled.setCheckable(True)
    if op.enabled:
        op_enabled.setCheckState(QtCore.Qt.Checked)
    else:
        op_enabled.setCheckState(QtCore.Qt.Unchecked)
    row.append(op_enabled)

然后您可以将插槽连接到模型的 itemChanged 信号,只要检查状态发生变化,它就会更新值:

class Browser(QtGui.QDialog):
    ...    
    def initUI(self):
        ...    
        self.ui_print.clicked.connect(self.print_info)

        self.items_model.itemChanged.connect(self.handleItemChanged)

    def handleItemChanged(self, item):
        if item.isCheckable():
            op = item.data(QtCore.Qt.UserRole)
            op.enabled = item.checkState() == QtCore.Qt.Checked