Создать pyqtSignals из словаря - PullRequest
1 голос
/ 26 марта 2019

Ну, я писал сценарий для программного обеспечения, разработанного на Python, в котором я буду слишком часто использовать сигналы и слоты в приложении PyQt5.У меня появилась идея создать словарь, в который входят все сигналы, и каждый сигнал будет иметь свой собственный ключ для доступа (или, по сути, для подключения его к функции).Проблема в том, что я получаю эту ошибку 'AttributeError:' PyQt5.QtCore.pyqtSignal 'объект по какой-то причине не имеет атрибута' connect '.Я прочитал об этой ошибке и обнаружил, что мне нужно объявить сигналы вне конструктора, чтобы она заработала, но, к сожалению, это сломает мою идею, поэтому я пришел сюда, чтобы кто-то мог решить мою проблему.

Воткод, если вы все еще не понимаете:

from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtCore import QRunnable, pyqtSlot, QThreadPool, QObject, pyqtSignal

class WorkerSignals(QObject):
    signals = {}

    def __init__(self, **kwargs):
        QObject.__init__(self)
        if (kwargs is not None):
            for key, value in kwargs.items():
                self.signals[key] = value

class Worker(QRunnable):
    def __init__(self, fn, *args, **kwargs):
        super(Worker, self).__init__()
        self.fn = fn
        self.args = args
        self.kwargs = kwargs

    @pyqtSlot()
    def run(self):
        self.fn(*self.args, **self.kwargs)

и пример создания сигналов:

worker_signals = WorkerSignals(result=pyqtSignal(str), error=pyqtSignal(str))
worker_signals.signals['result'].connect(self.on_receive_result)
worker_signals.signals['error'].connect(self.on_receive_error)

1 Ответ

2 голосов
/ 26 марта 2019

Как указано в документах :

Сигнал (в частности, несвязанный сигнал) является атрибутом класса.Когда сигнал упоминается как атрибут экземпляра класса, тогда PyQt5 автоматически связывает экземпляр с сигналом, чтобы создать связанный сигнал.[...]

Таким образом, не только необходимо, чтобы он был объявлен вне конструктора, но он должен быть статическим атрибутом, поскольку он служит прототипом для создания сигналов, принадлежащих экземпляру.Возможное решение - использовать тип для создания динамических классов:

from PyQt5 import QtCore

d = {
    "result": QtCore.pyqtSignal(str),
    "error": QtCore.pyqtSignal(str)
}

WorkerSignals = type("WorkerSignals", (QtCore.QObject,), d)

if __name__ == '__main__':
    import sys
    app = QtCore.QCoreApplication(sys.argv)
    worker_signals = WorkerSignals()

    def on_result(text):
        print("result:", text)

    def on_error(text):
        print("error:", text)

    worker_signals.result.connect(on_result)
    worker_signals.error.connect(on_error)

    def emit_result():
        worker_signals.result.emit(" 1+1=2 ")
    def emit_error():
        worker_signals.error.emit(" :( ")

    QtCore.QTimer.singleShot(1000, emit_result)
    QtCore.QTimer.singleShot(2000, emit_error)

    QtCore.QTimer.singleShot(3000, app.quit)
    sys.exit(app.exec_())
...