QtCore.Signal 和 SIGNAL 有什么区别?

Lor*_*sum 1 python pyqt pyside

我正在阅读使用 Python 和 Qt 进行快速 GUI 编程。它于 2008 年发布,在 PyQt4.5 引入 API 更改之前。

是什么SIGNAL()以及它是如何从不同PySideSignal()与PyQt的的pyqtSignal()班?

我找不到任何旧文档。但是,我看到了许多用于将信号连接到插槽的旧式语法:

self.connect(self, SIGNAL('valueChanged(int)'), my_slot)
Run Code Online (Sandbox Code Playgroud)

我不清楚它SIGNAL是函数、类方法还是类,是否用于定义新信号,以及是否仍受支持。那里有很多旧代码,我不确定如何解释。

eyl*_*esc 5

SIGNAL 是一种实现 Qt 宏 SIGNAL 的方法,该宏存在于 PyQt4 / PySide / PySide2 中,而不再存在于 pyqt5 中。

要了解其中的区别,您必须了解 Qt 中的不同连接语法:

  • 老款式:
connect(sender, SIGNAL(foo_signal(parameters)), receiver, SLOT(foo_slot(parameters))
Run Code Online (Sandbox Code Playgroud)
  • 新风格:
connect(sender, &Sender_Klass::foo_signal, receiver, &Receiver_Klass::foo_slot)
Run Code Online (Sandbox Code Playgroud)

主要区别是:

  • 在运行时或编译时验证信号和槽的存在,
  • 如果插槽不一定是 QSlot 但它们可以是任何功能。

欲了解更多信息,请阅读此处。目前推荐使用第二种方法,因为它可以预见错误。


考虑到上述情况,PyQt4 的最新版本和 PyQt5 从一开始就通过允许声明信号的 pyqtSignal(PySide 中的信号)实现了新的声明语法。

总之,SIGNAL 是旧连接样式的残余,它仍然在 PySide2 中工作,但不再在 PyQt5 中工作,此方法允许在运行时创建信号。另一方面,pyqtSignal 或 Signal 允许我们在创建类时声明信号。

以下示例显示了差异:

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_()
Run Code Online (Sandbox Code Playgroud)
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_()
Run Code Online (Sandbox Code Playgroud)

更详细地说,第一种方法在运行时创建修改 QMetaObject 的信号,这可能会导致问题,因为 QMetaObject 具有可以在某些优化中考虑的预定顺序。因此,当使用第一种方法时,它会启动警告并失败:

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_()
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)

因此,因此,目前不建议在 PySide2 和 PyQt5 的最新版本中使用 SIGNAL,而是建议使用新的语法。