Search code examples
pythonpython-3.xpyqtpyqt5qlistview

Remove multi-selected rows correctly from QListView


I am having issues trying to correctly delete multiple selected rows from a QListView. It works correctly selecting items going from top to bottom, but when you select multiple rows going from bottom to top, it keeps one of the selected rows in the view.

How can I fix this to where it correctly removes all selected rows in any order the user chooses?

Example:

Selecting the rows in this order gives an invalid solution: Level5, Level3, Level2

Removes only Level2

Changing to for items in self.listView.selectedIndexes(): works the opposite to where you cannot select from top to bottom.

from PyQt5 import QtCore, QtGui, QtWidgets
import sys,functools

class Window(QtWidgets.QMainWindow):
    def __init__(self, parent = None):
        super(Window,self).__init__(parent)
        self.setCentralWidget(QtWidgets.QWidget(self))
        self.setWindowTitle('GUI')
        mainlayout = QtWidgets.QVBoxLayout()
        #Information for widgets
        self.items = {'Level1':1,'Level2':2,'Level3':3,'Level4':4,'Level5':5,'Level6':6}
        #LineEdit1
        self.button = QtWidgets.QPushButton()
        self.button.setText('Remove Selected Items')
        firstBox = QtWidgets.QHBoxLayout()
        firstBox.addWidget(self.button)
        #ListView
        self.listView = QtWidgets.QListView()
        self.listView.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
        secondBox = QtWidgets.QVBoxLayout()
        secondBox.addWidget(self.listView)

        #Add Layouts
        mainlayout.addLayout(firstBox)
        mainlayout.addLayout(secondBox)
        self.centralWidget().setLayout(mainlayout)
        #Model
        self.model = QtGui.QStandardItemModel()
        self.listView.setModel(self.model)

        self.button.clicked.connect(functools.partial(self.selecteditems,self.model))
        self.fillModel(self.model)

    def fillModel(self,model):
        for level in self.items:
            item = QtGui.QStandardItem(str(level))
            model.appendRow(item)

    def selecteditems(self,model):
        if len(self.listView.selectedIndexes()) > 1:
            for items in reversed(self.listView.selectedIndexes()):
                model.takeRow(items.row()) #works correctly selecting items from top to bottom, but doesn't work when selecting bottom to top
def main():
    app = QtWidgets.QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec_())



if __name__ == '__main__':
    main()

Solution

  • you can also use just reversed and sorted:

    def selecteditems(self,model):
        if len(self.listView.selectedIndexes()) > 1:
            for items in reversed(sorted(self.listView.selectedIndexes())):
                model.takeRow(items.row())