Qt源码阅读(一) 信号槽的连接与调用

科技资讯 投稿 6900 0 评论

Qt源码阅读(一) 信号槽的连接与调用

信号槽连接

目录
    信号槽连接
    • 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;
    }

上面主要都是一些基本的信号连接的判断,主要是:

    信号和槽的参数数量
  1. 信号和槽的参数是否兼容
  2. 信号和槽的返回值是否兼容

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;
   

编程笔记 » Qt源码阅读(一) 信号槽的连接与调用

赞同 (40) or 分享 (0)
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽