Why does pyqtSlot decorator cause "TypeError: connect() failed"?
Why does pyqtSlot decorator cause "TypeError: connect() failed"?
我有这个 Python 3.5.1 程序,带有 PyQt5 和从 QtCreator ui 文件创建的 GUI,其中 pyqtSlot 装饰器导致 "TypeError: connect() failed between textChanged(QString) and edited()".
在重现问题的示例代码中,我有 2 个自定义 classes:MainApp 和 LineEditHandler。 MainApp 实例化主 GUI(来自文件 "mainwindow.ui"),LineEditHandler 处理 QLineEdit 对象。 LineEditHandler 存在的原因是将主要与 QLineEdit 对象相关的自定义方法集中在 class 中。它的构造函数需要 QLineEdit 对象和 MainApp 实例(在需要时访问其他 objects/properties)。
在 MainApp 中,我将 QLineEdit 的 textChanged 信号连接到 LineEditHandler.edited()。如果我不使用 pyqtSlot() 装饰 LineEditHandler.edited() 一切正常。如果我确实使用 @pyqtSlot() 作为方法,代码 运行 将失败并返回 "TypeError: connect() failed between textChanged(QString) and 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()
我不知道出了什么问题,但我找到了解决方法:将 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()
为什么要使用 @pyqtSlot
?
它失败的原因是 LineEditHandler
不是 QObject
。 @pyqtSlot
所做的基本上是创建一个真正的 Qt 插槽,而不是在内部使用代理对象(这是没有 @pyqtSlot
的默认行为)。
我有这个 Python 3.5.1 程序,带有 PyQt5 和从 QtCreator ui 文件创建的 GUI,其中 pyqtSlot 装饰器导致 "TypeError: connect() failed between textChanged(QString) and edited()".
在重现问题的示例代码中,我有 2 个自定义 classes:MainApp 和 LineEditHandler。 MainApp 实例化主 GUI(来自文件 "mainwindow.ui"),LineEditHandler 处理 QLineEdit 对象。 LineEditHandler 存在的原因是将主要与 QLineEdit 对象相关的自定义方法集中在 class 中。它的构造函数需要 QLineEdit 对象和 MainApp 实例(在需要时访问其他 objects/properties)。
在 MainApp 中,我将 QLineEdit 的 textChanged 信号连接到 LineEditHandler.edited()。如果我不使用 pyqtSlot() 装饰 LineEditHandler.edited() 一切正常。如果我确实使用 @pyqtSlot() 作为方法,代码 运行 将失败并返回 "TypeError: connect() failed between textChanged(QString) and 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()
我不知道出了什么问题,但我找到了解决方法:将 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()
为什么要使用 @pyqtSlot
?
它失败的原因是 LineEditHandler
不是 QObject
。 @pyqtSlot
所做的基本上是创建一个真正的 Qt 插槽,而不是在内部使用代理对象(这是没有 @pyqtSlot
的默认行为)。