QtCore.Signal和SIGNAL有什么区别?

问题描述

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

SIGNAL()是什么,它与PySide Signal()和PyQt的pyqtSignal()类有什么区别?

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

self.connect(self,SIGNAL('valueChanged(int)'),my_slot)

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

解决方法

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

要了解差异,您必须了解Qt中的不同连接语法:

  • 旧样式:
connect(sender,SIGNAL(foo_signal(parameters)),receiver,SLOT(foo_slot(parameters))
  • 新样式:
connect(sender,&Sender_Klass::foo_signal,&Receiver_Klass::foo_slot)

主要区别在于:

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

有关更多信息,请阅读here。目前建议使用第二种方法,因为它可以预见错误。


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

总而言之,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_()
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_()

更详细地讲,第一种方法会在运行时创建修改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,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,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,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

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

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...