Qt中的SIGNAL和SLOT宏:它们是做什么用的?

11

我是Qt的初学者,正在努力理解SIGNALSLOT宏。在学习使用connect方法绑定信号和槽时,我发现Qt官方参考页面上的教程使用:

connect(obj1, SIGNAL(signal(int)), obj2, SLOT(slot()))

然而,这个方法也非常有效:

connect(obj1, &Obj1::signal, obj2, &Obj2::slot)
所以,宏SIGNALSLOT具体是做什么的?它们只是在对象所属的类中查找信号并返回其地址吗?
那么为什么大多数程序员使用这些宏,而不是使用&Obj1::signal,因为后者似乎更简单,并且如果信号函数的参数发生变化,您不需要更改代码?
4个回答

9

在Qt 5之前,使用SIGNALSLOT宏是建立连接的唯一方式。连接在运行时进行,并要求在头文件中标记信号和槽。例如:

Class MyClass : public QObject
{
    Q_OBJECT
    signals:
        void Signal();

    slots:
        void ASlotFunction();
};

为了避免重复,它的工作方式在QT 4文档中描述
信号和槽机制是Qt提供的C++扩展的一部分,并利用元对象编译器(moc)这篇文章解释了为什么信号和槽使用moc。
第二个connect方法得到了很大改进,因为指定的函数可以在编译时检查,而不是运行时。此外,通过使用函数的地址,您可以引用任何类函数,而不仅仅是标记为slots的函数: 文档已更新至Qt 5
此外,关于Qt 4 connect工作原理有一篇很好的博客文章在这里,Qt 5 在这里

6

补充第一个答案。

宏SIGNAL和SLOT到底是做什么的?

几乎什么也没做。看一下qobjectdefs.h

# define SLOT(a)     "1"#a
# define SIGNAL(a)   "2"#a

它只是添加了12。这意味着下一行代码是有效的,并且能够按照预期工作:
QObject *obj = new QObject;
connect(obj,"2objectNameChanged(QString)",this,"1show()");//suppose this is a pointer to a QDialog subclass
obj->setObjectName("newNAme");

大多数程序员为什么使用这些宏而不是像 &Obj1::signal 这样的方式呢?
  • 因为这些宏不仅适用于Qt5。
  • 因为使用这些宏可以避免处理重载信号时带来的复杂性(可能会使代码变得混乱,而且并不简单)。
  • 因为在新语法中,有时需要使用特定的断开连接方式。

更多细节请参见此处。


你真的是想说“这些宏不仅在Qt5中工作”吗?还是别的什么意思? - Peter Mortensen
@PeterMortensen 是的,因为宏方式适用于Qt4和Qt5,但是指向方法的新方式仅适用于Qt5,所以我才这样写。那些使用旧代码的开发人员无法使用Qt5,因此他们无法使用新方式,只能使用旧方式,因为“旧方式不仅适用于Qt5”。 - Jablonski

2
为了完善TheDarkKnight的答案,将使用旧版Qt 4 SIGNAL和SLOT宏的旧代码重构为使用函数地址的Qt 5新语法是一种极佳实践。
编译时将突然出现连接错误,而不是在运行时!因为只要有拼写错误就会导致Qt 4出错。此外,如果有全名空间,则函数名称必须是完全限定名称。
另一个好处是能够使用lambda作为slot函数,这可以减少对命名函数的需求,特别是当slot体非常简单时。

0

这些宏只是将它们的参数转换为特定于信号/槽的字符串。基于字符串和基于函数对象的连接之间的区别 可在文档中找到。简而言之:

基于字符串:

  • 类型检查在运行时完成
  • 可以将信号连接到具有比信号更多参数的槽(使用默认参数)
  • 可以将 C++ 函数连接到 QML 函数

基于函数对象:

  • 类型检查在编译时完成
  • 可以执行隐式类型转换
  • 可以将信号连接到 lambda 表达式

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接