<p>正如<a href="http://pyqt.sourceforge.net/Docs/PyQt5/signals_slots.html#unbound-and-bound-signals" rel="nofollow noreferrer">docs</a>所指出的:</p>
<blockquote>
<p>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. This is the same mechanism that Python itself
uses to create bound methods from class functions.</p>
</blockquote>
<p>信号声明为类的属性,但通过self引用时,会与对象绑定,即声明的信号与实例化的信号不同:</p>
<pre><code>from PyQt5 import QtCore
class Foo(QtCore.QObject):
fooSignal = QtCore.pyqtSignal()
print("declared:", fooSignal)
def __init__(self, parent=None):
super(Foo, self).__init__(parent)
print("instantiated:", self.fooSignal)
if __name__ == '__main__':
import sys
app = QtCore.QCoreApplication(sys.argv)
obj = Foo()
</code></pre>
<p>输出:</p>
<pre><code>declared: <unbound PYQT_SIGNAL )>
instantiated: <bound PYQT_SIGNAL fooSignal of Foo object at 0x7f4beb998288>
</code></pre>
<p>这就是产生错误的原因,因此,如果要使用信号,必须使用对象获取信号,以便我们可以检查属性并获取信号:</p>
<pre><code>from PyQt5 import QtCore, QtGui, QtWidgets
class Widget(QtWidgets.QWidget):
foo = QtCore.pyqtSignal(str)
bar = QtCore.pyqtSignal(str)
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
self.fill_signals()
self.names = ["foo", "bar"]
self.btn_go = QtWidgets.QPushButton("Go")
self.mywidgets = {}
for name in self.names:
self.mywidgets[name] = QtWidgets.QLineEdit()
signal = self.mysignals.get(name)
if signal is not None:
signal.connect(self.mywidgets[name].setText)
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.btn_go)
for name in self.names:
layout.addWidget(self.mywidgets[name])
self.btn_go.clicked.connect(self.testing)
def fill_signals(self):
self.mysignals = dict()
for p in dir(self):
attr = getattr(self, p)
if isinstance(attr, QtCore.pyqtBoundSignal):
self.mysignals[p] = attr
def testing(self):
self.foo.emit("foo")
self.bar.emit("bar")
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
</code></pre>