从字典创建 pyqtSignals
Create pyqtSignals from dictionary
好吧,我正在编写一个通过 Python 设计的软件,我将在 PyQt5 应用程序中过多地使用信号和槽。我想到了创建一个字典,其中所有信号都会进入,每个信号都有自己的密钥以便访问(或基本上将其连接到一个函数)。问题是我得到这个错误'AttributeError: 'PyQt5.QtCore.pyqtSignal' object has no attribute '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)
如docs所示:
A signal (specifically an unbound signal) is a class attribute. When a
signal is referenced as an attribute of an instance of the class then
PyQt5 automatically binds the instance to the signal in order to
create a bound signal. [...]
因此,它不仅需要在构造函数外部声明,而且必须是静态属性,因为它用作创建属于实例的信号的原型。一种可能的解决方案是使用类型创建动态 类:
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_())
好吧,我正在编写一个通过 Python 设计的软件,我将在 PyQt5 应用程序中过多地使用信号和槽。我想到了创建一个字典,其中所有信号都会进入,每个信号都有自己的密钥以便访问(或基本上将其连接到一个函数)。问题是我得到这个错误'AttributeError: 'PyQt5.QtCore.pyqtSignal' object has no attribute '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)
如docs所示:
A signal (specifically an unbound signal) is a class attribute. When a signal is referenced as an attribute of an instance of the class then PyQt5 automatically binds the instance to the signal in order to create a bound signal. [...]
因此,它不仅需要在构造函数外部声明,而且必须是静态属性,因为它用作创建属于实例的信号的原型。一种可能的解决方案是使用类型创建动态 类:
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_())