QMetaObject::connectSlotsByName详解

一、介绍

如果使用ui acton编辑器,一般在代码中找不到生成的connnect函数,即关联信号与槽的函数,那么,信号与槽是怎么样关联起来的呢?答案就是靠这个函数connectSlotsByName来实现的。

二、使用方法

查看QT助手,其函数原型是这样的:

[static] void QMetaObject::connectSlotsByName(QObject *object)

给出的说明:递归搜索给定对象的所有子对象,并将来自这些子对象的匹配信号连接到以下形式的对象插槽:

void on_<object name>_<signal name>(<signal parameters>);

假设我们的对象有一个类型为QPushButton的子对象,对象名为button1。捕捉按钮的clicked()信号的槽是:

void on_button1_clicked();

如果对象本身具有正确设置的对象名称,则其自身的信号也将连接到其各自的插槽。

综上所述,只要槽函数名规则是这样的:on_子对象名_信号名,如:

   public slots:
    void on_actionNew_triggered();

就可以不用写connect函数来连接信号和槽了!但是需要注意的是:

1、尽量不要让QObject出现相同的objectName

2、如果同名,connectSlotsByName只会给其中一个建立缺省的信号槽的连接

三、解析

为什么QObject不能出现相同的objectName呢?

因为connectSlotsByName 函数内查找object对象的children使用了objectname()这个函数
也就是这一句源码:

QByteArray objName = co->objectName().toAscii();

从 Qt助手的文档中看到

objectName : QString
This property holds the name of this object.
You can find an object by name (and type) using findChild(). You can find a set of objects with findChildren().
By default, this property contains an empty string.

如果对象有children,那么这个children默认的 objectName属性缺省情况下是空串,而在使用ui的时候connectSlotsByName有效,是因为ui文件保证了这些子体的objectName都非空。可以查看一下ui生成的.h文件, 发现所有的子对象,都使用了setObjectName(),而setObjectName(),显然就是给这些对象的objectName赋值。

源码:

void QMetaObject::connectSlotsByName(QObject *o)
{
    if (!o)
        return;
    const QMetaObject *mo = o->metaObject();
    Q_ASSERT(mo);
    const QObjectList list = qFindChildren<QObject *>(o, QString());
    for (int i = 0; i < mo->methodCount(); ++i) {
        const char *slot = mo->method(i).signature();
        Q_ASSERT(slot);
        if (slot[0] != 'o' || slot[1] != 'n' || slot[2] != '_')
            continue;
        bool foundIt = false;
        for(int j = 0; j < list.count(); ++j) {
            const QObject *co = list.at(j);
            QByteArray objName = co->objectName().toAscii();
            int len = objName.length();
            if (!len || qstrncmp(slot + 3, objName.data(), len) || slot[len+3] != '_')
                continue;
            int sigIndex = co->d_func()->signalIndex(slot + len + 4);
            if (sigIndex < 0) { // search for compatible signals
                const QMetaObject *smo = co->metaObject();
                int slotlen = qstrlen(slot + len + 4) - 1;
                for (int k = 0; k < co->metaObject()->methodCount(); ++k) {
                    QMetaMethod method = smo->method(k);
                    if (method.methodType() != QMetaMethod::Signal)
                        continue;

                    if (!qstrncmp(method.signature(), slot + len + 4, slotlen)) {
                        int signalOffset, methodOffset;
                        computeOffsets(method.enclosingMetaObject(), &signalOffset, &methodOffset);
                        sigIndex = k + - methodOffset + signalOffset;
                        break;
                    }
                }
            }
            if (sigIndex < 0)
                continue;
            if (QMetaObjectPrivate::connect(co, sigIndex, o, i)) {
                foundIt = true;
                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)) {
            qWarning("QMetaObject::connectSlotsByName: No matching signal for %s", slot);
        }
    }

参考:

Qt信号与槽之connectSlotsByName函数_Linux编程_Linux公社-Linux系统门户网站

Qt connectSlotsByName与信号槽_丸子叮咚响的博客-CSDN博客_connectslotsbyname

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值