QT 自带槽函数的绑定时机

1.背景:
需要确定在ui中直接点击转到槽生成的槽函数是什么时候和信号绑定的,从而确定此槽函数被调用的时机。
2.结论:
在调用以下函数后,qt自带的信号与槽就绑定了。

ui->setupUi(this);

3.原因:
1)qt文档解释:
在Using a Designer UI File in Your Application 中Widgets and Dialogs with Auto-Connect提到

Although it is easy to implement a custom slot in the dialog and connect it in the constructor, we could instead use QMetaObject’s auto-connection facilities to connect the OK button’s clicked() signal to a slot in our subclass. uic automatically generates code in the dialog’s setupUi() function to do this, so we only need to declare and implement a slot with a name that follows a standard convention:

即在调用setupUi的时候会自动进行绑定。
2)qt代码实现:
在编译生成的ui_xxx.h中,setupUI函数创建了各个控件之后,在函数的最后会去调用
QMetaObject::connectSlotsByName(QObject *object);
此函数在qobjectdefs.h中声明

// internal slot-name based connect
  static void connectSlotsByName(QObject *o);

奇怪的是,它的定义是在qobject.cpp中。

/*!
    \fn void QMetaObject::connectSlotsByName(QObject *object)

    Searches recursively for all child objects of the given \a object, and connects
    matching signals from them to slots of \a object that follow the following form:

    \snippet code/src_corelib_kernel_qobject.cpp 33


    Let's assume our object has a child object of type \c{QPushButton} with
    the \l{QObject::objectName}{object name} \c{button1}. The slot to catch the
    button's \c{clicked()} signal would be:

    \snippet code/src_corelib_kernel_qobject.cpp 34


    If \a object itself has a properly set object name, its own signals are also
    connected to its respective slots.

    \sa QObject::setObjectName()
 */
void QMetaObject::connectSlotsByName(QObject *o)
{
    if (!o)
        return;
    const QMetaObject *mo = o->metaObject();
    Q_ASSERT(mo);
    const QObjectList list = // list of all objects to look for matching signals including...
            o->findChildren<QObject *>(QString()) // all children of 'o'...
            << o; // and the object 'o' itself

    // for each method/slot of o ...
    for (int i = 0; i < mo->methodCount(); ++i) {//此处可得知,会去循环绑定子控件的信号与槽。所以一般setupUi传的是this也能绑定所有的控件。
        const QByteArray slotSignature = mo->method(i).methodSignature();
        const char *slot = slotSignature.constData();
        Q_ASSERT(slot);

        // ...that starts with "on_", ...
        if (slot[0] != 'o' || slot[1] != 'n' || slot[2] != '_')
            continue;

        // ...we check each object in our list, ...
        bool foundIt = false;
        for(int j = 0; j < list.count(); ++j) {
            const QObject *co = list.at(j);
            const QByteArray coName = co->objectName().toLatin1();

            // ...discarding those whose objectName is not fitting the pattern "on_<objectName>_...", ...
            if (coName.isEmpty() || qstrncmp(slot + 3, coName.constData(), coName.size()) || slot[coName.size()+3] != '_')
                continue;

            const char *signal = slot + coName.size() + 4; // the 'signal' part of the slot name

            // ...for the presence of a matching signal "on_<objectName>_<signal>".
            const QMetaObject *smeta;
            int sigIndex = co->d_func()->signalIndex(signal, &smeta);
            if (sigIndex < 0) {
                // if no exactly fitting signal (name + complete parameter type list) could be found
                // look for just any signal with the correct name and at least the slot's parameter list.
                // Note: if more than one of thoses signals exist, the one that gets connected is
                // chosen 'at random' (order of declaration in source file)
                QList<QByteArray> compatibleSignals;
                const QMetaObject *smo = co->metaObject();
                int sigLen = qstrlen(signal) - 1; // ignore the trailing ')'
                for (int k = QMetaObjectPrivate::absoluteSignalCount(smo)-1; k >= 0; --k) {
                    const QMetaMethod method = QMetaObjectPrivate::signal(smo, k);
                    if (!qstrncmp(method.methodSignature().constData(), signal, sigLen)) {
                        smeta = method.enclosingMetaObject();
                        sigIndex = k;
                        compatibleSignals.prepend(method.methodSignature());
                    }
                }
                if (compatibleSignals.size() > 1)
                    qWarning() << "QMetaObject::connectSlotsByName: Connecting slot" << slot
                               << "with the first of the following compatible signals:" << compatibleSignals;
            }

            if (sigIndex < 0)
                continue;

            // we connect it...
            if (Connection(QMetaObjectPrivate::connect(co, sigIndex, smeta, o, i))) {
                foundIt = true;
                // ...and stop looking for further objects with the same name.
                // Note: the Designer will make sure each object name is unique in the above
                // 'list' but other code may create two child objects with the same name. In
                // this case one is chosen 'at random'.
                break;
            }
        }
        if (foundIt) {
            // we found our slot, now skip all overloads   连接了一个之后,就不会再连接同槽函数的重载。而这一个 是随机。不是指定的顺序
            while (mo->method(i + 1).attributes() & QMetaMethod::Cloned)
                  ++i;
        } else if (!(mo->method(i).attributes() & QMetaMethod::Cloned)) {
            // check if the slot has the following signature: "on_..._...(..."
            int iParen = slotSignature.indexOf('(');
            int iLastUnderscore = slotSignature.lastIndexOf('_', iParen-1);
            if (iLastUnderscore > 3)
                qWarning("QMetaObject::connectSlotsByName: No matching signal for %s", slot);
        }
    }
}

根据源码可以得知:
1、在绑定的时候,会去遍历子类的信号与槽,然后实现绑定;
2、槽函数只能是指定的格式,且存在重载的时候(Designer会确保不会有重载,但用户可能会自己去重载槽函数),只会绑定一个,且是随机的。

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值