Search code examples
pythonpyqtpyqt5qlistwidgetqlistwidgetitem

PyQt5 TypeError for openPersitentEditor


Hi everyone so I was doing some exam prep with PYQT5 and I created an application from an exercise in my workbook where we have to make it display a list of courses and when you click them it opens a message box with the course name also there is a button so that the user can add a course to the list. The add button is suppoused to open a QlineEdit on the last item in the listWidget, so the user can edit the field however I keep getting a TypeError message:

line 67, in onAddButton self.mylistWidget.openPersistentEditor(self, modelItem) TypeError: openPersistentEditor(self, QListWidgetItem): argument 1 has unexpected type 'UNISACourses'

import sys
from PyQt5.QtWidgets import (QListWidget, QLineEdit, QWidget, QMessageBox, QHBoxLayout, QAbstractItemView,
                             QApplication, QVBoxLayout, QPushButton, QButtonGroup)
from PyQt5.QtCore import pyqtSlot
from PyQt5 import Qt, QtGui


class MyListWidget(QListWidget, QLineEdit, QWidget):
    """
    Subclassed QListWidget to allow for the closing of open editors and other modifications
    """

    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self.setSelectionMode(QAbstractItemView.ExtendedSelection)

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Return:
            print("Closing any persistent editor")
            self.closePersistentEditor(self.model().index(self.count() - 1))
        else:
            super().keyPressEvent(event)


class UNISACourses(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        # Main Window Settings
        self.setGeometry(300, 300, 350, 250)
        self.setWindowTitle('Courses')

        # Layout
        self.main_layout = QVBoxLayout(self)
        self.setLayout(self.main_layout)

        # Main Widget
        self.mylistWidget = MyListWidget()
        self.mylistWidget.addItems(["COS1511", "COS1521", "COS1512", "MNB1512", "INF1505", "FAC1502"])
        self.main_layout.addWidget(self.mylistWidget)

        # Define a layout for the other buttons to exist in for flexibility with resizing
        self.btn_add = QPushButton("Add", clicked=self.onAddButton)
        self.btn_delete = QPushButton("Delete", clicked=self.onDeleteButton)
        hbox = QHBoxLayout()
        hbox.addWidget(self.btn_add)
        hbox.addWidget(self.btn_delete)
        self.main_layout.addLayout(hbox)

        # Define any additional behavior of the list
        self.mylistWidget.itemDoubleClicked.connect(self.onClicked)

    def onClicked(self, item):
        QMessageBox.information(self, "Info", item.text())

    @pyqtSlot()
    def onAddButton(self):
        """
        Opens a QLineEdit editor on the last item in the listwidget, allowing the user to edit the field.
        NOTE: The user must click outside of the editor field then press Enter in order to close the editor
        """
        self.mylistWidget.addItem('')
        modelItem = self.mylistWidget.model().index(self.mylistWidget.count() - 1)
        self.mylistWidget.openPersistentEditor(self, modelItem)

    @pyqtSlot()
    def onDeleteButton(self):
        for item in self.mylistWidget.selectedItems():
            self.mylistWidget.takeItem(self.mylistWidget.row(item))


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = UNISACourses()
    ex.show()
    sys.exit(app.exec_())

Solution

  • You are passing two incorrect arguments (self and a QModelIndex) to QListWidget.openPersistentEditor which accepts one QListWidgetItem. Use the QListWidget.item method to get the item. You can also add QListWidget.setCurrentItem so it gets selected right away and ready to edit.

    def onAddButton(self):
        self.mylistWidget.addItem('')
        modelItem = self.mylistWidget.item(self.mylistWidget.count() - 1)
        self.mylistWidget.openPersistentEditor(modelItem)
        self.mylistWidget.setCurrentItem(modelItem)
    

    Same fix here:

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Return:
            print("Closing any persistent editor")
            self.closePersistentEditor(self.item(self.count() - 1))
        else:
            super().keyPressEvent(event)
    

    Also the Qt Namespace class for Qt.Key_Return is inside the QtCore Module.

    from PyQt5.QtCore import pyqtSlot, Qt
    from PyQt5 import QtGui