Reputation: 4534
I'm reading Rapid GUI programming with Python and Qt. It was published in 2008, prior to the API change intoduced in PyQt4.5.
What was SIGNAL()
and how is it different from the PySide Signal()
and PyQt's pyqtSignal()
classes?
I can't find any old documentation. However, I see lots of the old-style syntax for connecting signals to slots:
self.connect(self, SIGNAL('valueChanged(int)'), my_slot)
It's not clear to me if SIGNAL
is a function, classmethod, or class, if it was used to define new signals, and if it's still supported. There's a lot of old code out there I'm not sure how to interpret.
Upvotes: 1
Views: 4457
Reputation: 243993
SIGNAL is a method that implements the Qt macro SIGNAL that is present in PyQt4 / PySide / PySide2 and no longer in pyqt5.
To understand the difference, you must understand the different connection syntax in Qt:
connect(sender, SIGNAL(foo_signal(parameters)), receiver, SLOT(foo_slot(parameters))
connect(sender, &Sender_Klass::foo_signal, receiver, &Receiver_Klass::foo_slot)
The main differences are:
For more information read here. Currently the second method is recommended as it foresees bugs.
Considering the above, the last releases of PyQt4 and from the beginning PyQt5 implements the new declaration syntax through pyqtSignal (Signal in PySide) that allows to declare signals.
In conclusion, SIGNAL is a remnant of the old connection style that still works in PySide2 but no longer in PyQt5, this method allows to create signals in runtime. On the other hand, pyqtSignal or Signal allow us to declare signals when creating the class.
The following example shows the differences:
from PySide2 import QtCore
class Foo(QtCore.QObject):
def __init__(self, parent=None):
super().__init__(parent)
self.connect(self, QtCore.SIGNAL("foo()"), self.slot_foo)
def slot_foo(self):
print("bye")
QtCore.QCoreApplication.quit()
def send_signal(self):
self.emit(QtCore.SIGNAL("foo()"))
app = QtCore.QCoreApplication([])
foo = Foo()
QtCore.QTimer.singleShot(1000, foo.send_signal)
app.exec_()
from PySide2 import QtCore
class Foo(QtCore.QObject):
foo = QtCore.Signal()
def __init__(self, parent=None):
super().__init__(parent)
self.foo.connect(self.slot_foo)
def slot_foo(self):
print("bye")
QtCore.QCoreApplication.quit()
def send_signal(self):
self.foo.emit()
app = QtCore.QCoreApplication([])
foo = Foo()
QtCore.QTimer.singleShot(1000, foo.send_signal)
app.exec_()
Going into more detail, the first method creates signals in runtime that modify the QMetaObject and that can cause an issue since the QMetaObject has a predetermined order that can be taken into account in some optimization. Therefore, when using the first method, it will launch the warning and it fails:
from PySide2 import QtCore
class Foo(QtCore.QObject):
def __init__(self, parent=None):
super().__init__(parent)
self.connect(self, QtCore.SIGNAL("bar()"), self.slot_bar)
self.connect(self, QtCore.SIGNAL("foo()"), self.slot_foo)
def slot_foo(self):
print("ok")
self.emit(QtCore.SIGNAL("foo()"))
def slot_bar(self):
print("bye")
QtCore.QCoreApplication.quit()
def send_signal(self):
print("send foo signal")
self.emit(QtCore.SIGNAL("foo()"))
app = QtCore.QCoreApplication([])
foo = Foo()
QtCore.QTimer.singleShot(1000, foo.send_signal)
app.exec_()
main.py:8: RuntimeWarning:
*** Sort Warning ***
Signals and slots in QMetaObject 'Foo' are not ordered correctly, this may lead to issues.
1 Signal bar()
2 Slot slot_bar()
3! Signal foo()
self.connect(self, QtCore.SIGNAL("foo()"), self.slot_foo)
main.py:8: RuntimeWarning:
*** Sort Warning ***
Signals and slots in QMetaObject 'Foo' are not ordered correctly, this may lead to issues.
1 Signal bar()
2 Slot slot_bar()
3! Signal foo()
4! Slot slot_foo()
self.connect(self, QtCore.SIGNAL("foo()"), self.slot_foo)
main.py:26: RuntimeWarning:
*** Sort Warning ***
Signals and slots in QMetaObject 'Foo' are not ordered correctly, this may lead to issues.
1 Signal bar()
2 Slot slot_bar()
3! Signal foo()
4! Slot slot_foo()
5! Slot send_signal()
app.exec_()
send
So, therefore, it is not recommended to use SIGNAL currently in the recent versions of PySide2 and PyQt5, but rather the new syntax.
Upvotes: 5