信号槽连接
目录
-
信号槽连接
- 1. 信号的连接
- 2 槽的调用
connect函数时,将槽的一系列信息,封装成一个Connection
,在发送信号时,通过这个列表,去回调槽函数。
1. 信号的连接
//Connect a signal to a pointer to qobject member function
// QtPrivate::FunctionPointer<Func1>::Object返回发送信号的对象类型
template <typename Func1, typename Func2>
static inline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
const typename QtPrivate::FunctionPointer<Func2>::Object *receiver, Func2 slot,
Qt::ConnectionType type = Qt::AutoConnection
{
typedef QtPrivate::FunctionPointer<Func1> SignalType;
typedef QtPrivate::FunctionPointer<Func2> SlotType;
Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
"No Q_OBJECT in the class with the signal";
//compilation error if the arguments does not match.
// 检查信号和槽参数是否一致
Q_STATIC_ASSERT_X(int(SignalType::ArgumentCount >= int(SlotType::ArgumentCount,
"The slot requires more arguments than the signal provides.";
// 检查信号和槽参数是否兼容
Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value,
"Signal and slot arguments are not compatible.";
// 检查信号和槽的返回值是否兼容
Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<typename SlotType::ReturnType, typename SignalType::ReturnType>::value,
"Return type of the slot is not compatible with the return type of the signal.";
const int *types = nullptr;
// SignalType -> QtPrivate::FunctionPointer<Func1>
// QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types( 返回信号参数的值对应的元类型id列表
if (type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection
types = QtPrivate::ConnectionTypes<typename SignalType::Arguments>::types(;
return connectImpl(sender, reinterpret_cast<void **>(&signal,
receiver, reinterpret_cast<void **>(&slot,
new QtPrivate::QSlotObject<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotType::ArgumentCount>::Value,
typename SignalType::ReturnType>(slot,
type, types, &SignalType::Object::staticMetaObject;
}
上面主要都是一些基本的信号连接的判断,主要是:
- 信号和槽的参数数量
- 信号和槽的参数是否兼容
- 信号和槽的返回值是否兼容
QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signal,
const QObject *receiver, void **slot,
QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type,
const int *types, const QMetaObject *senderMetaObject
{
if (!signal {
qWarning("QObject::connect: invalid nullptr parameter";
if (slotObj
slotObj->destroyIfLastRef(;
return QMetaObject::Connection(;
}
int signal_index = -1;
void *args[] = { &signal_index, signal };
// 根据调用来判断是否存在信号,如果当前类没有就去父类中寻找
// 直到找到信号或者是最基层的类
// 找到信号的index和信号的对象
for (; senderMetaObject && signal_index < 0; senderMetaObject = senderMetaObject->superClass( {
senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args;
if (signal_index >= 0 && signal_index < QMetaObjectPrivate::get(senderMetaObject->signalCount
break;
}
if (!senderMetaObject {
qWarning("QObject::connect: signal not found in %s", sender->metaObject(->className(;
slotObj->destroyIfLastRef(;
return QMetaObject::Connection(nullptr;
}
// 信号下标
signal_index += QMetaObjectPrivate::signalOffset(senderMetaObject;
return QObjectPrivate::connectImpl(sender, signal_index, receiver, slot, slotObj, type, types, senderMetaObject;
}
同样,我们对这个函数进行分析,第一个片段是对信号发送者是否为空指针的一个判断
if (!signal {
qWarning("QObject::connect: invalid nullptr parameter";
if (slotObj
slotObj->destroyIfLastRef(;
return QMetaObject::Connection(;
}
第二个片段是去找到信号发送者(sender的元对象类型(Meta Object以及信号在对象信号中的位置。如果当前对象没有该信号,就去其父类对象去找。直到找到为止。
for (; senderMetaObject && signal_index < 0; senderMetaObject = senderMetaObject->superClass( {
senderMetaObject->static_metacall(QMetaObject::IndexOfMethod, 0, args;
if (signal_index >= 0 && signal_index < QMetaObjectPrivate::get(senderMetaObject->signalCount
break;
}
然后就是进一步调用其内部实现:
QMetaObject::Connection QObjectPrivate::connectImpl(const QObject *sender, int signal_index,
const QObject *receiver, void **slot,
QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type,
const int *types, const QMetaObject *senderMetaObject
{
// 发送对象、接收对象、槽函数对象、信号发送的元对象都不为空 2023-3-11
if (!sender || !receiver || !slotObj || !senderMetaObject {
// 任意一个为空,报错且清理空间,并返回
const char *senderString = sender ? sender->metaObject(->className(
: senderMetaObject ? senderMetaObject->className(
: "Unknown";
const char *receiverString = receiver ? receiver->metaObject(->className(
: "Unknown";
qWarning("QObject::connect(%s, %s: invalid nullptr parameter", senderString, receiverString;
if (slotObj
slotObj->destroyIfLastRef(;
return QMetaObject::Connection(;
}
// 去掉const的发送和接受对象
QObject *s = const_cast<QObject *>(sender;
QObject *r = const_cast<QObject *>(receiver;
// 顺序锁,按照顺序依次去对mutex去上锁
// 这里依次对发送和接收者的信号去上锁
QOrderedMutexLocker locker(signalSlotLock(sender,
signalSlotLock(receiver;
if (type & Qt::UniqueConnection && slot && QObjectPrivate::get(s->connections.loadRelaxed( {
// ObjectPrivate::get(s 获取s对应的d指针
// connections 维护了所有的信号槽连接
QObjectPrivate::ConnectionData *connections = QObjectPrivate::get(s->connections.loadRelaxed(;
if (connections->signalVectorCount( > signal_index {
// 获取信号的连接
const QObjectPrivate::Connection *c2 = connections->signalVector.loadRelaxed(->at(signal_index.first.loadRelaxed(;
// 循环遍历
while (c2 {
// 如果已经存在信号和槽的连接,且为uniqueConnection,则返回
if (c2->receiver.loadRelaxed( == receiver && c2->isSlotObject && c2->slotObj->compare(slot {
slotObj->destroyIfLastRef(;
return QMetaObject::Connection(;
}
c2 = c2->nextConnectionList.loadRelaxed(;
}
}
// 将type与UniqueConnection进行异或,去掉UniqueConnection
type = static_cast<Qt::ConnectionType>(type ^ Qt::UniqueConnection;
}
// 创建一个新的连接
std::unique_ptr<QObjectPrivate::Connection> c{new QObjectPrivate::Connection};
c->sender = s;
c->signal_index = signal_index;
QThreadData *td = r->d_func(->threadData;
td->ref(;
c->receiverThreadData.storeRelaxed(td;
c->receiver.storeRelaxed(r;
c->slotObj = slotObj;
c->connectionType = type;