Qt 中的 SIGNAL 和 SLOT 宏:它们的作用是什么?
SIGNAL & SLOT macros in Qt : what do they do?
我是 Qt 的初学者,正在尝试理解 SIGNAL
和 SLOT
宏。在学习使用connect
方法绑定信号槽时,发现Qt官方参考页面上的教程使用:
connect(obj1, SIGNAL(signal(int)), obj2, SLOT(slot()))
然而,这也很有效:
connect(obj1, &Obj1::signal, obj2, &Obj2::slot)
那么宏 SIGNAL
和 SLOT
到底做了什么?他们只是在对象所属的 class 中寻找信号和 return 它的地址吗?
那为什么大多数程序员都使用这些宏而不是使用&Obj1::signal
,因为后者看起来更简单,而且如果信号函数的参数发生变化也不需要更改代码?
在 Qt 5 之前,使用 SIGNAL
和 SLOT
宏曾经是建立连接的唯一方法。连接是在运行时建立的,需要在中标记信号和槽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:
的部分
第一个答案的补充。
what exactly did the macro SIGNAL and SLOT do
几乎没有。看看 qobjectdefs.h
:
# define SLOT(a) "1"#a
# define SIGNAL(a) "2"#a
它只是添加 1
或 2
。这意味着下一个代码有效并按预期工作:
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)
- 因为使用新语法,您有时需要使用特定的
断开连接
为了完成 ,将使用旧 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
我是 Qt 的初学者,正在尝试理解 SIGNAL
和 SLOT
宏。在学习使用connect
方法绑定信号槽时,发现Qt官方参考页面上的教程使用:
connect(obj1, SIGNAL(signal(int)), obj2, SLOT(slot()))
然而,这也很有效:
connect(obj1, &Obj1::signal, obj2, &Obj2::slot)
那么宏 SIGNAL
和 SLOT
到底做了什么?他们只是在对象所属的 class 中寻找信号和 return 它的地址吗?
那为什么大多数程序员都使用这些宏而不是使用&Obj1::signal
,因为后者看起来更简单,而且如果信号函数的参数发生变化也不需要更改代码?
在 Qt 5 之前,使用 SIGNAL
和 SLOT
宏曾经是建立连接的唯一方法。连接是在运行时建立的,需要在中标记信号和槽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:
的部分第一个答案的补充。
what exactly did the macro SIGNAL and SLOT do
几乎没有。看看 qobjectdefs.h
:
# define SLOT(a) "1"#a
# define SIGNAL(a) "2"#a
它只是添加 1
或 2
。这意味着下一个代码有效并按预期工作:
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)
- 因为使用新语法,您有时需要使用特定的 断开连接
为了完成
突然间,连接错误会出现在编译时而不是运行时!很容易出现 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