最近几天研究了一下信号和槽,总结一下。直接上干货,少写千篇一律的内容。
Qt的信号和槽是解决两个以及多个QObject对象通信的问题,拿A B C三个对象举例,A对象可以自定义信号并且发出信号,B和C对象可以作为观察者监听A的信号。A对象发出信号的时候,B和C的槽函数会被调用。
其中关键的函数是QObject::connect函数和关键字emit。
- connect函数
connect函数负责生成被观察者和观察者的连接信息,这些连接信息可以是一对多的,多对多的,多对一的。具体执行的时机是在信号发射的时候。
QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal,
const QObject *receiver, const char *method,
Qt::ConnectionType type)
- Qt::ConnectionType
connect函数的最后一个参数是指定信号和槽的连接方式:
Qt::DirectConnection: 相当于函数的直接调用
Qt::QueuedConnection: 异步调用
Qt::AutoConnection: 如果发送者在emit的时候所在的线程等于接受者所依附的线程,则为同步调用,否则为上面的异步调用方式
Qt::BlockingQueuedConnection:同步调用
Qt::UniqueConnection:单一连接 - emit
emit是核心,把信号和什么槽进行连接以及以什么方式连接进行处理,我们要重点关注这个函数。在qt里,emit其实为空(看下面的宏定义)
# define emit
写上emit是为了保持代码的可读性,如果不写也没问题,但是建议写上,一份好的代码肯定是便于阅读的。比如声明的信号 signal_fun,用过Qt的都知道,我们在代码里是不用实现signal_fun这个函数的,原因是因为Qt为了实现信号与槽,引入了元对象系统,moc编译器会实现这些函数。实际上在emit的时候会调用下面的函数:
void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_index, void **argv)
{
int signal_index = signalOffset + local_signal_index;
//发送者阻塞标志位true,不执行槽函数,直接返回
if (sender->d_func()->blockSig)
return;
Q_TRACE_SCOPE(QMetaObject_activate, sender, signal_index);
if (sender->d_func()->isDeclarativeSignalConnected(signal_index)
&& QAbstractDeclarativeData::signalEmitted) {
Q_TRACE_SCOPE(QMetaObject_activate_declarative_signal, sender, signal_index);
QAbstractDeclarativeData::signalEmitted(sender->d_func()->declarativeData, sender,
signal_index, argv);
}
if (!sender->d_func()->isSignalConnected(signal_index, /*checkDeclarative =*/ false)
&& !qt_signal_spy_callback_set.signal_begin_callback
&& !qt_signal_spy_callback_set.signal_end_callback) {
// The possible declarative connection is done, and nothing else is connected, so:
return;
}
void *empty_argv[] = {
0 };
if (qt_signal_spy_callback_set.signal_begin_callback != 0) {
qt_signal_spy_callback_set.signal_begin_callback(sender, signal_index,
argv ? argv : empty_argv);
}
{
QMutexLocker locker(signalSlotLock(sender));
struct ConnectionListsRef {
QObjectConnectionListVector *connectionLists;
ConnectionListsRef(QObjectConnectionListVector *connectionLists) : connectionLists(connectionLists)
{
if (connectionLists)
++connectionLists->inUse;
}
~ConnectionListsRef(