信号和槽机制
一种回调机制,信号发出后根据连接方式选择什么时候调用回调函数。可以实现跨线程的调用
连接方式
常用自动连接、直接连接、队列连接,阻塞队列链接
Qt::AutoConnection(默认值)
如果接收者位于发出信号的线程中,则使用Qt:::DirectConnection。否则,将使用Qt::QueuedConnection。连接类型是在发出信号时确定的。
Qt::DirectConnection
槽函数运行在发信号的线程里面。信号发出时,槽函数立即被调用,此时 eimt(signal) = slotFunction()。只有当槽函数运行完毕之后eimt(signal) 之后的代码才会被执行
Qt::QueuedConnection
槽函数运行在接收者的线程里, 只有当控制权返回到接收线程的事件循环时,槽函数被调用。
调用此链接时时槽函数调用不是立即进行:
当信号发射和槽函数在同一个线程时,这个线程会先执行完毕当前eimt()之后的代码。执行完毕以后这个线程的事件循环才会继续去调用槽函数。
当信号发色和槽不在同一个线程的时候,槽函数具体调用时机不定,看接收信号的线程
Qt::BlockingQueuedConnection
与Qt:∶QueuedCnnection相同,但发射信号的线程会被阻塞直到槽函数返回。如果接收者所在的线程就是发射信号的线程,会导致死锁。阻塞指的是阻塞该线程的业务代码和事件循环。
信号槽相关宏定义
#define signals public //将signals定义为public
#define slots //slots定义是一个空宏,可省
#define Q_OBJECT \ //定义一些元对象,和元调用相关的东西。是信号槽实现的核心机制
public: \
QT_WARNING_PUSH \
Q_OBJECT_NO_OVERRIDE_WARNING \
static const QMetaObject staticMetaObject; \
virtual const QMetaObject *metaObject() const; \
virtual void *qt_metacast(const char *); \
virtual int qt_metacall(QMetaObject::Call, int, void **); \
QT_TR_FUNCTIONS \
private: \
Q_OBJECT_NO_ATTRIBUTES_WARNING \
Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); \
QT_WARNING_POP \
struct QPrivateSignal {}; \
QT_ANNOTATE_CLASS(qt_qobject, "")
#define emit //emit 定义是一个空宏,可省
#define SIGNAL(a) "2"#a //"2"加上一个#a, 其中#a就是一个字符串, 例如SIGNAL(valueChanged(int))宏展开后就是"2"valueChanged(int)"
#define SLOT(a) "1"#a //"1"加上一个#a
信号和槽的连接
Qt信号的一些介绍可以参考下面文档。槽就是一个普通的成员函数,可以是私有也可以是公有
Qt:信号
1、当我们们在cpp文件中使用 emit mySignal()
发送一个信号时,其实就是进行一次信号函数的调用。上面讲过emit宏定义是空的, emit mySignal()
被元对象编译器编译后就会变成 mySignal()
,运行时就相当于运行在相应的moc_xxx.cpp文件中实现的函数体中的内容。
2、在信号函数内,如下图的两个自动生成的信号函数,主要执行的就是Qt元对象QMetaObject的activate函数,该函数将对象指针,元对象引用(staticMetaObject),信号对应的唯一序号标识(按照cpp文件顺序给的), 参数一起传入,并根据信号标识去查找connectList列表,如果有的话就会按照设置的调用方式(Qt::Directconnect等)启动槽函数。
// SIGNAL 0
void SystemService::show_a_message(QString _t1)
{
void *_a[] = { nullptr, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
QMetaObject::activate(this, &staticMetaObject, 0, _a);
}
// SIGNAL 1
void SystemService::show_a_frameless_message(QString _t1, int _t2)
{
void *_a[] = { nullptr, const_cast<void*>(reinterpret_cast<const void*>(&_t1)), const_cast<void*>(reinterpret_cast<const void*>(&_t2)) };
QMetaObject::activate(this, &staticMetaObject, 1, _a);
}