当 QListview 项的复选框更改时发出信号

Emit Signal when QListview item's checkbox changes

如何在 qlistview 项目的复选框更改时发出信号?理想情况下,发出的信号会有某种指向发生变化的项目的指针,这样我就可以在 PySide 中采取相应的行动。

import os
import sys
import json
from PySide import QtGui, QtCore 


class MegaMergeWindow(QtGui.QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MegaMergeWindow, self).__init__(*args, **kwargs)
        self.TITLE = 'Mega Merge'
        self.VERSION = '1.0.0'
        self.setWindowTitle(self.TITLE + ' | ' + self.VERSION)
        self.resize(350,500)

        # vars
        self.user_folder = os.path.join(os.getenv('LOCALAPPDATA'), 'MegaMerge')

        # controls
        self.ui_files = QtGui.QListView()
        self.ui_files.setModel(QtGui.QStandardItemModel())
        self.ui_files.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)

        self.ui_merge = QtGui.QPushButton('Merge')

        main_layout = QtGui.QVBoxLayout()
        main_layout.addWidget(self.ui_files)
        main_layout.addWidget(self.ui_merge)

        main_widget = QtGui.QWidget()
        main_widget.setLayout(main_layout)
        self.setCentralWidget(main_widget)

        # signals
        self.ui_merge.clicked.connect(self.merge_clicked)
        self.populate_files()


    def populate_files(self, files=[], clear=False):
        model = self.ui_files.model()

        if clear:
            model.clear()

        files = ['Doug','Kevin','Amy','Melissa','John']

        for f in files:
            name = os.path.basename(f)
            item = QtGui.QStandardItem(name)
            item.setData(f, role=QtCore.Qt.UserRole)
            item.setCheckable(True)
            item.setCheckState(QtCore.Qt.Checked)
            model.appendRow(item)
        model.sort(0, QtCore.Qt.AscendingOrder)


    def collect_paths(self):
        files = []
        model = self.ui_files.model()
        for index in range(model.rowCount()):
            item = model.item(index)
            if item.checkState() == QtCore.Qt.Checked:
                files.append(item.text())
        return files


    def merge_files(self, files=[]):
        print files


    def merge_clicked(self):
        files = self.collect_paths()
        print files


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


if __name__ == '__main__':
    main()

在Qt4中没有信号指示是否检查QCheckBoxQAbstractItemView,只是在Qt5中修改了dataChanged信号以发送被修改的角色,因此区分检查是否被更改。

在 Qt4 中,有几种方法可以创建该信号,一种方法是使用委托来跟踪该角色的变化,如下所示:

class StyledItemDelegate(QtGui.QStyledItemDelegate):
    checked = QtCore.Signal(QtCore.QModelIndex, int)
    def editorEvent(self, event, model, option, index):
        if model.flags(index) & QtCore.Qt.ItemIsUserCheckable:
            # before the change
            last_value = index.data(QtCore.Qt.CheckStateRole)
        value = QtGui.QStyledItemDelegate.editorEvent(self, event, model, option, index)
        if model.flags(index) & QtCore.Qt.ItemIsUserCheckable:
            # after the change
            new_value = index.data(QtCore.Qt.CheckStateRole)
            if last_value != new_value:
                self.checked.emit(index, new_value)
        return value

class MegaMergeWindow(QtGui.QMainWindow):
    def __init__(self, *args, **kwargs):
        [...]

        # controls
        self.ui_files = QtGui.QListView()
        self.ui_files.setModel(QtGui.QStandardItemModel())
        self.ui_files.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
        delegate = StyledItemDelegate()
        delegate.checked.connect(self.on_checked)
        self.ui_files.setItemDelegate(delegate)
        [...]

    def on_checked(self, index, state):
        text = "Checked" if state == QtCore.Qt.Checked else "UnChecked"
        item = self.ui_files.model().itemFromIndex(index)
        print(item, item.data())
        print(index, index.data())
        print(state)
        print(text)