歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Qt信號與槽之connectSlotsByName函數

如果使用ui acton編輯器,一般在代碼中找不到生成的connnect函數,即關聯信號與槽的函數,那麼,信號與槽是怎麼樣關聯起來的呢?

是靠這個函數connectSlotsByName來實現的。至於更詳細的原理性的細節,研究了一天只有一點點進展。我暫時不想探究了,以後有機會在

研究。下面摘錄了一篇文章,算是這個問題暫時夠一段落。

現象:

在實驗自動連接槽和信號的時候,發現如果不使用ui文件, 則似乎函數無效
而同樣ui文件中也是使用 connectSlotsByName() 來完成關聯的,單獨提出來使用則似乎沒有效果,感覺很是奇怪

原因:

connectSlotsByName 函數內查找object對象的children使用了objectname()函數
也就是這一句下文附的源碼中這一句
QByteArray objName = co->objectName().toAscii();

從 doc中看到
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賦值。

解決辦法:
如果不使用ui文件, 那麼仍想使用connectSlotsByName來自動關聯signal 和 slot, 那麼應該使用setObjectName()函數。

附 connectSlotByName源碼:
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);
        }
    }

Copyright © Linux教程網 All Rights Reserved