1

I can figure out how to check if all checkboxes are checked, by iterating over a QListView, like explained here

But is there a way to connect to a function, right at the time of checking an individual box, which also might not be the same as the currently selected object in the QListView? E.g. the equivalent of self.listview.clicked.connect(foo)

Minimal combined with linked example above:

from PyQt5 import QtCore

from PyQt5 import QtGui
from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import QApplication, QWizardPage, QListView


class AppRemovalPage(QWizardPage):
    def __init__( self, parent ):
        super(AppRemovalPage, self).__init__(parent)
        self.setTitle('Apps to Remove')
        self.setSubTitle('Listview')
        self.list_view = QListView(self)
        self.list_view.setMinimumSize(465, 200)
        self.isWritten = False

        self.model = QtGui.QStandardItemModel(self.list_view)
        for line in ('a', 'b', 'c', 'd', 'e'):
            self.item = QtGui.QStandardItem(line)
            self.item.setCheckable(True)
            self.item.setCheckState(QtCore.Qt.Unchecked)
            self.model.appendRow(self.item)

        self.list_view.setModel(self.model)
        self.list_view.clicked.connect(self.getSelectedListItem)

        self.list_view.show()


    def print_checked_items(self):
        for index in range(self.model.rowCount()):
            item = self.model.item(index)
            if item.checkState() == QtCore.Qt.Checked:
                print(item.text(), "was checked")
        print("rerun timed script to list checked objects again")



    def getSelectedListItem(self):
        """
        Gets the name and row of the selected object.
        """
        currentSelection = self.list_view.selectedIndexes()

        name  = None
        row   = None
        index = None

        # Set name for currently selected object in listview
        for obj_index in currentSelection:
            item  = self.model.itemFromIndex(obj_index)
            row   = item.row()
            index = self.model.index(row, 0)
            name  = self.model.data(index)

        self.currName  = name
        self.currRow   = row
        self.currIndx  = index

        print(self.currName)


app = QApplication([])
listview = AppRemovalPage(None)
listview.show()
QTimer.singleShot(5000, listview.print_checked_items)
app.exec_()
komodovaran_
  • 1,940
  • 16
  • 44

1 Answers1

1

For this case we can use a delegate to detect the change of state, another solution is to use the model but this would be more annoying to implement since each model would have to be modified. The solution is the next

import sys

from PyQt5 import QtCore, QtGui, QtWidgets


class Delegate(QtWidgets.QStyledItemDelegate):
    def editorEvent(self, event, model, option, index):
        checked = index.data(QtCore.Qt.CheckStateRole)
        ret = QtWidgets.QStyledItemDelegate.editorEvent(self, event, model, option, index)
        if checked != index.data(QtCore.Qt.CheckStateRole):
            self.parent().checked.emit(index)
        return ret


class ListView(QtWidgets.QListView):
    checked = QtCore.pyqtSignal(QtCore.QModelIndex)
    def __init__(self, *args, **kwargs):
        super(ListView, self).__init__(*args, **kwargs)
        self.setItemDelegate(Delegate(self))


class AppRemovalPage(QtWidgets.QWizardPage):
    def __init__( self, parent=None):
        super(AppRemovalPage, self).__init__(parent)
        self.setTitle('Apps to Remove')
        self.setSubTitle('Listview')
        self.list_view = ListView(self)
        self.list_view.setMinimumSize(465, 200)

        self.model = QtGui.QStandardItemModel(self)
        for line in ('a', 'b', 'c', 'd', 'e'):
            self.item = QtGui.QStandardItem(line)
            self.item.setCheckable(True)
            self.item.setCheckState(QtCore.Qt.Unchecked)
            self.model.appendRow(self.item)

        self.list_view.setModel(self.model)
        self.list_view.checked.connect(self.onChecked)

    @QtCore.pyqtSlot(QtCore.QModelIndex)
    def onChecked(self, index):
        item = self.model.itemFromIndex(index)
        if item.checkState() == QtCore.Qt.Checked:
            print(item.text(), "was checked")
        else:
            print(item.text(), "was unchecked")

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    listview = AppRemovalPage()
    listview.show()
    sys.exit(app.exec_())
eyllanesc
  • 235,170
  • 19
  • 170
  • 241