2016-11-18 2 views
1

У меня есть эта программа Python 3.5.1 с PyQt5 и графический интерфейс, созданный из файла QtCreator ui, где декоратор pyqtSlot вызывает «Ошибка TypeError: connect() между textChanged (QString) и отредактированным()».Почему декоратор pyqtSlot вызывает «TypeError: connect() failed»?

В примере кода для воспроизведения проблемы у меня есть 2 пользовательских класса: MainApp и LineEditHandler. MainApp создает основной графический интерфейс (из файла «mainwindow.ui»), а LineEditHandler обрабатывает объект QLineEdit. Причина LineEditHandler заключается в том, чтобы сконцентрировать пользовательские методы, которые в основном относятся к объекту QLineEdit в классе. Его конструктору нужен объект QLineEdit и экземпляр MainApp (для доступа к другим объектам/свойствам при необходимости).

В MainApp я подключаю сигнал TextChanged от QLineEdit к LineEditHandler.edited(). Если я не украшаю LineEditHandler.edited() с pyqtSlot(), все работает отлично. Если я использую метод @pyqtSlot() для этого метода, прогон кода завершится неудачей с «Ошибка TypeError: connect() между textChanged (QString) и отредактированным()». Что я здесь делаю неправильно?

Вы можете получить файл 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() 
+0

То, что вы делаете неправильно, слепо использует 'pyqtSlot', не понимая, для чего это необходимо и когда оно действительно необходимо. – ekhumoro

+0

Это не ответ. Если я столкнулся с этой проблемой и спросил, что это потому, что я не эксперт, та же самая позиция, что все были в какой-то момент. – R01k

ответ

0

Я не знаю, что было неправильно, но я нашел обходной путь: Подключите сигнал TextChanged к pyqtSlot украшенного метода MainApp, который вызывает 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() 
1

Почему вы хотите использовать @pyqtSlot?

Причина, по которой это не удается, заключается в том, что LineEditHandler не является QObject. То, что @pyqtSlot действительно создает настоящий слот Qt вместо внутреннего использования прокси-объекта (это поведение по умолчанию без @pyqtSlot).

+0

Я хочу '@ pyqtSlot', потому что отредактированный() является слотом для сигнала textChanged. Хотя '@ pyqtSlot' здесь не требуется, рекомендуется использовать его для всех слотов. Если '@ pyqtSlot' не может использоваться вне QObjects, почему его можно использовать в модулях, которые не имеют классов? – R01k

+0

@ R01k. Конечно, не рекомендуется использовать его для всех слотов - я не знаю, откуда вы это делаете. – ekhumoro

+0

Я слышал, что рекомендуется подключать сигнал к слотам. Когда это делается по потокам, это очень желательно. Опять же, это именно то, что я слышал. – R01k

Смежные вопросы