JokerMartini
JokerMartini

Reputation: 6147

Emit Signal when QListview item's checkbox changes

How can i emit a signal when a qlistview item's checkbox is changed? Ideally the emitted signal would have some sort of pointer to the item that changed so i could act accordingly in PySide.

enter image description here

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()

Upvotes: 3

Views: 2070

Answers (1)

eyllanesc
eyllanesc

Reputation: 243907

In Qt4 there is no signal indicating that if QCheckBox is checked or not QAbstractItemView, just in Qt5 the dataChanged signal was modified to send the role that was modified and therefore distinguish if the checked was changed or not.

In Qt4 there are several alternatives to create that signal, one way is to use a delegate to track the change of that role as I show below:

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)

Upvotes: 2

Related Questions