为什么pyqtSlot装饰器导致" TypeError:connect()失败"?

时间:2016-11-18 10:37:40

标签: python-3.x typeerror connect pyqt5 qstring

我有这个带有PyQt5的Python 3.5.1程序和一个从QtCreator ui文件创建的GUI,其中pyqtSlot装饰器导致" TypeError:connect()在textChanged(QString)和edited()"之间失败。

在重现问题的示例代码中,我有2个自定义类:MainApp和LineEditHandler。 MainApp实例化主GUI(来自文件" mainwindow.ui"),LineEditHandler处理QLineEdit对象。 LineEditHandler存在的原因是集中主要与类中的QLineEdit对象相关的自定义方法。它的构造函数需要QLineEdit对象和MainApp实例(在需要时访问其他对象/属性)。

在MainApp中,我将QLineEdit的textChanged信号连接到LineEditHandler.edited()。如果我不用pyqtSlot()装饰LineEditHandler.edited(),一切正常。如果我对方法使用@pyqtSlot(),则代码运行将失败,并且" TypeError:connect()在textChanged(QString)和edited()"之间失败。我在这里做错了什么?

您可以在https://drive.google.com/file/d/0B70NMOBg3HZtUktqYVduVEJBN2M/view

获取mainwindow.ui文件

这是产生问题的示例代码:

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()

2 个答案:

答案 0 :(得分:4)

为什么要使用@pyqtSlot

失败的原因是LineEditHandler不是QObject@pyqtSlot的作用基本上是创建一个真正的Qt槽而不是内部使用代理对象(这是没有@pyqtSlot的默认行为)。

答案 1 :(得分:1)

我不知道出了什么问题,但我找到了一个解决方法:将textChanged信号连接到调用LineEditHandler.edited()的pyqtSlot装饰MainApp方法:

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()