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

SIGNAL & SLOT macros in Qt : what do they do?

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

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

然而,这也很有效:

connect(obj1, &Obj1::signal, obj2, &Obj2::slot)

那么宏 SIGNALSLOT 到底做了什么?他们只是在对象所属的 class 中寻找信号和 return 它的地址吗?

那为什么大多数程序员都使用这些宏而不是使用&Obj1::signal,因为后者看起来更简单,而且如果信号函数的参数发生变化也不需要更改代码?

在 Qt 5 之前,使用 SIGNALSLOT 宏曾经是建立连接的唯一方法。连接是在运行时建立的,需要在中标记信号和槽header。例如:

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

    slots:
        void ASlotFunction();
};

为避免重复,描述了它的工作方式in the QT 4 documentation

信号和槽机制是 Qt 提供的 C++ 扩展的一部分,并利用 Meta Object Compiler (moc)

This 解释了为什么信号和插槽使用 moc。

第二种连接方法有了很大改进,因为可以在编译时检查指定的函数,而不是运行时。此外,通过使用函数的地址,您可以引用任何 class 函数,而不仅仅是那些标记为 slots:

的部分

documentation was updated for Qt 5.

此外,还有一篇关于 Qt 4 连接工作的好博客 post here and Qt 5 here

第一个答案的补充。

what exactly did the macro SIGNAL and SLOT do

几乎没有。看看 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");

why do most programmers use these macros instead of using like &Obj1::signal

  • 因为这些宏不仅适用于 Qt5。
  • 因为有了这些宏,重载就不复杂了 信号 (it can make your code very dirty and it is really not a simple thing)
  • 因为使用新语法,您有时需要使用特定的 断开连接

More details here.

为了完成 ,将使用旧 Qt 4 SIGNAL 和 SLOT 宏的遗留代码重构为使用函数地址的 Qt 5 新语法是一个很好的做法。

突然间,连接错误会出现在编译时而不是运行时!很容易出现 Qt 4 连接错误,因为任何拼写错误都会导致此类错误。另外,函数的名称必须是完全限定名称,即如果有的话,前面有完整的命名空间。

另一个好处是可以对槽函数使用 lambda,如果槽主体很普通,这可以减少对命名函数的需求。

这些宏只是将它们的参数转换为 signal/slot-specific 字符串。 Differences between String-Based and Functor-Based Connections 可以在文档中找到。简而言之:

String-based:

  • Type checking is done at Run-time
  • Can connect signals to slots which have more arguments than the signal (using default parameters)
  • Can connect C++ functions to QML functions

Functor-based:

  • Type checking is done at Compile-time
  • Can perform implicit type conversions
  • Can connect signals to lambda expressions