【问题标题】:Why does pyqtSlot decorator cause "TypeError: connect() failed"?为什么 pyqtSlot 装饰器会导致“TypeError: connect() failed”?
【发布时间】:2017-04-02 04:16:42
【问题描述】:

我有这个 Python 3.5.1 程序,它带有 PyQt5 和一个从 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() 之间失败”。我在这里做错了什么?

mainwindow.ui 文件获取地址:https://drive.google.com/file/d/0B70NMOBg3HZtUktqYVduVEJBN2M/view

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

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

【问题讨论】:

  • 这是一个非答案。如果我遇到这个问题并问这是因为我不是专家,那么每个人在某个时候都处于相同的位置。

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


【解决方案1】:

为什么要使用@pyqtSlot

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

【讨论】:

  • 我想要@pyqtSlot,因为edited() 是textChanged 信号的插槽。虽然这里没有特别要求@pyqtSlot,但建议将其用于所有插槽。如果@pyqtSlot不能在QObjects之外使用,为什么可以在没有类的模块中使用?
  • @R01k。当然不建议将它用于所有插槽 - 我不知道你从哪里得到它。
  • 我听说建议在将信号连接到插槽时使用。当它跨线程完成时,这是非常可取的。再说一次,这正是我所听到的。
  • @R01k。好吧,你可能从one of the many answers 那里听说过这个话题。
  • @ekhumoro 我知道@pyqtslot 被推荐在任何插槽之前以获得速度和内存性能,除了moveToThread 问题。但根据你的解释,这个装饰器实际上是可以避免的。
【解决方案2】:

我不知道出了什么问题,但我找到了解决方法:将 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()

【讨论】:

    猜你喜欢
    • 2018-04-17
    • 2023-04-03
    • 2017-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-08
    相关资源
    最近更新 更多