I have this Python 3.5.1 program with PyQt5 and a GUI created from a QtCreator ui file where the pyqtSlot decorator causes "TypeError: connect() failed between textChanged(QString) and edited()".
In the sample code to reproduce the problem I have 2 custom classes: MainApp and LineEditHandler. MainApp instantiates the main GUI (from the file "mainwindow.ui") and LineEditHandler handles a QLineEdit object. LineEditHandler reason to exist is to concentrate the custom methods that relate mostly to the QLineEdit object in a class. Its constructor needs the QLineEdit object and the MainApp instance (to access other objects/properties when needed).
In MainApp I connect the textChanged signal of the QLineEdit to LineEditHandler.edited(). If I don't decorate LineEditHandler.edited() with pyqtSlot() everything works fine. If I do use @pyqtSlot() for the method, the code run will fail with "TypeError: connect() failed between textChanged(QString) and edited()". What am I doing something wrong here?
You can get the mainwindow.ui file at: https://drive.google.com/file/d/0B70NMOBg3HZtUktqYVduVEJBN2M/view
And this is the sample code to generate the problem:
import sys
from PyQt5 import uic
from PyQt5.QtWidgets import *
from PyQt5.QtCore import pyqtSlot
Ui_MainWindow, QtBaseClass = uic.loadUiType("mainwindow.ui")
class MainApp(QMainWindow, Ui_MainWindow):
    def __init__(self):
        # noinspection PyArgumentList
        QMainWindow.__init__(self)
        Ui_MainWindow.__init__(self)
        self.setupUi(self)
        # Instantiate the QLineEdit handler.
        self._line_edit_handler = LineEditHandler(self, self.lineEdit)
        # Let the QLineEdit handler deal with the QLineEdit textChanged signal.
        self.lineEdit.textChanged.connect(self._line_edit_handler.edited)
class LineEditHandler:
    def __init__(self, main_window, line_edit_obj):
        self._line_edit = line_edit_obj
        self._main_window = main_window
    # FIXME The pyqtSlot decorator causes "TypeError: connect() failed between
    # FIXME textChanged(QString) and edited()"
    @pyqtSlot(name="edited")
    def edited(self):
        # Copy the entry box text to the label box below.
        self._main_window.label.setText(self._line_edit.text())
def main():
    app = QApplication(sys.argv)
    window = MainApp()
    window.show()
    sys.exit(app.exec_())
if __name__ == "__main__":
    main()
Why do you want to use @pyqtSlot?
The reason it fails is that LineEditHandler is not a QObject. What @pyqtSlot does is basically creating a real Qt slot instead of internally using a proxy object (which is the default behavior without @pyqtSlot).
I don't know what was wrong, but I found a workaround: Connect the textChanged signal to a pyqtSlot decorated MainApp method that calls LineEditHandler.edited():
import sys
from PyQt5 import uic
from PyQt5.QtWidgets import *
from PyQt5.QtCore import pyqtSlot
Ui_MainWindow, QtBaseClass = uic.loadUiType("mainwindow.ui")
class MainApp(QMainWindow, Ui_MainWindow):
    def __init__(self):
        # noinspection PyArgumentList
        QMainWindow.__init__(self)
        Ui_MainWindow.__init__(self)
        self.setupUi(self)
        # Instantiate the QLineEdit handler.
        self._line_edit_handler = LineEditHandler(self, self.lineEdit)
        self.lineEdit.textChanged.connect(self._line_edited)
        @pyqtSlot(name="_line_edited")
        def _line_edited(self):
            self._line_edit_handler.edited()
class LineEditHandler:
    def __init__(self, main_window, line_edit_obj):
        self._line_edit = line_edit_obj
        self._main_window = main_window
    def edited(self):
        # Copy the entry box text to the label box below.
        self._main_window.label.setText(self._line_edit.text())
def main():
    app = QApplication(sys.argv)
    window = MainApp()
    window.show()
    sys.exit(app.exec_())
if __name__ == "__main__":
    main()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With