QListView维护选择并选中所有选中项

时间:2019-04-18 00:16:43

标签: python pyside

我正在尝试找到一种方法来执行以下操作:

  • 当用户单击列表中的项目时,如果进行了选择,它将保留所选项目并更改其所有复选框以与单击的项目的复选框匹配

  • 在单击复选框时保持对项目的选择。当前,当单击选定行中的项目的复选框时,QListView会清除行选择。但是,当用户单击所选行之外的复选框时,它将正确保留选择。仅当用户单击该行而不是复选框时,该选择才会丢失。

有人可以帮助我覆盖单击复选框以实现我的目标时发生的情况吗?

enter image description here

import os, sys
from Qt import QtGui, QtWidgets, QtCore


class CheckableDictionaryListView(QtWidgets.QListView):

    def __init__(self, parent=None, **kwargs):
        super(CheckableDictionaryListView, self).__init__(parent)
        self.resize(300,300)
        self.filters = {}

        self.proxyModel = QtCore.QSortFilterProxyModel()
        self.proxyModel.setSortCaseSensitivity(QtCore.Qt.CaseInsensitive)
        self.proxyModel.setSourceModel(QtGui.QStandardItemModel())
        self.setModel(self.proxyModel)
        self.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
        self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
        self.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
        self.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred)
        self.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)

        # Begin
        self.setItems(['item 00','item 01','item 02','item 03','item 05','item 06','item 07','item 08','item 09','item 10'])


    # Methods
    def setItems(self, lst):
        model = self.model().sourceModel()
        model.clear()
        for x in lst:
            item = QtGui.QStandardItem()
            item.setCheckable(True)
            item.setData(x, role=QtCore.Qt.DisplayRole)
            model.appendRow(item)


def main():
    app = QtWidgets.QApplication(sys.argv)
    ex = CheckableDictionaryListView()
    ex.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    pass
    main()

1 个答案:

答案 0 :(得分:1)

除了覆盖editorEditor方法之外,还必须使用QAbstractItemView::MultiSelection作为selectionMode,以防止视图在单击复选框时被单击事件处理:

import os, sys
from Qt import QtGui, QtWidgets, QtCore


class StyledItemDelegate(QtWidgets.QStyledItemDelegate):
    def editorEvent(self, event, model, option, index):
        last_state = index.data(QtCore.Qt.CheckStateRole)
        val = super(StyledItemDelegate, self).editorEvent(
            event, model, option, index
        )
        if last_state != index.data(QtCore.Qt.CheckStateRole):
            return True
        return val


class CheckableDictionaryListView(QtWidgets.QListView):
    def __init__(self, parent=None):
        super(CheckableDictionaryListView, self).__init__(parent)
        delegate = StyledItemDelegate(self)
        self.setItemDelegate(delegate)
        self.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
        self.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
        self.setSizePolicy(
            QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred
        )
        self.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
        self.resize(300, 300)

        self.proxyModel = QtCore.QSortFilterProxyModel()
        self.proxyModel.setSortCaseSensitivity(QtCore.Qt.CaseInsensitive)
        self.proxyModel.setSourceModel(QtGui.QStandardItemModel(self))
        self.setModel(self.proxyModel)

        # after set model
        self.model().dataChanged.connect(self.onDataChanged)
        self.setItems(
            [
                "item 00",
                "item 01",
                "item 02",
                "item 03",
                "item 05",
                "item 06",
                "item 07",
                "item 08",
                "item 09",
                "item 10",
            ]
        )

    def setItems(self, lst):
        model = self.model().sourceModel()
        model.clear()
        for x in lst:
            item = QtGui.QStandardItem()
            item.setCheckable(True)
            item.setData(x, role=QtCore.Qt.DisplayRole)
            model.appendRow(item)

    @QtCore.Slot("QModelIndex", "QModelIndex", int)
    def onDataChanged(self, tl, br, roles):
        if QtCore.Qt.CheckStateRole in roles:
            if tl == br and tl in self.selectedIndexes():
                state = tl.data(QtCore.Qt.CheckStateRole)
                self.model().blockSignals(True)
                for ix in self.selectedIndexes():
                    self.model().setData(ix, state, QtCore.Qt.CheckStateRole)
                self.model().blockSignals(False)


def main():

    app = QtWidgets.QApplication(sys.argv)
    app.setStyle("fusion")
    ex = CheckableDictionaryListView()
    ex.show()
    sys.exit(app.exec_())


if __name__ == "__main__": 
    main()