如果使用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);
}
}