在测试的主窗口类构造函数在“ui->setupUi(this); ”语句前编写以下代码:php
QMetaObject::connectSlotsByName()这个函数会在ui->setupUi(this);里被调用执行。
而后在主窗口里增长下面的槽定义很代码:
html
而后编译运行,结果出来了:
9个按钮的objectName()都返回"TestButton"
只有第一个按钮的clicked信号被链接到了on_TestButton_clicked槽上
第 一个结论与个人猜测相符(后来看了QObject的源码,也是比较简单的),第二个结论与个人猜测有点不一样,我原本猜测,应该是9个按钮的clicked 信号应该均可以链接到这个on_TestButton_clicked槽上的,可是却只有第一个链接上了,这是为何呢?
让咱们看看connectSlotsByName都干了些什么吧。
connectSlotsByName的源码解读
函数
1 void QMetaObject::connectSlotsByName(QObject *o)
2 {
3 if (!o)
4 return;
5 const QMetaObject *mo = o->metaObject();
6 Q_ASSERT(mo);
7 const QObjectList list = qFindChildren<QObject *>(o, QString());
8 for (int i = 0; i < mo->methodCount(); ++i) {
9 const char *slot = mo->method(i).signature();
10 Q_ASSERT(slot);
11 if (slot[0] != 'o' || slot[1] != 'n' || slot[2] != '_')
12 continue;
13 bool foundIt = false;
14 for(int j = 0; j < list.count(); ++j) {
15 const QObject *co = list.at(j);
16 QByteArray objName = co->objectName().toAscii();
17 int len = objName.length();
18 if (!len || qstrncmp(slot + 3, objName.data(), len) || slot[len+3] != '_')
19 continue;
20 const QMetaObject *smo = co->metaObject();
21 int sigIndex = smo->indexOfMethod(slot + len + 4);
22 if (sigIndex < 0) { // search for compatible signals
23 int slotlen = qstrlen(slot + len + 4) - 1;
24 for (int k = 0; k < co->metaObject()->methodCount(); ++k) {
25 if (smo->method(k).methodType() != QMetaMethod::Signal)
26 continue;
27
28 if (!qstrncmp(smo->method(k).signature(), slot + len + 4, slotlen)) {
29 sigIndex = k;
30 break;
31 }
32 }
33 }
34 if (sigIndex < 0)
35 continue;
36 if (QMetaObject::connect(co, sigIndex, o, i)) {
37 foundIt = true;
38 break;
39 }
40 }
41 if (foundIt) {
42 // we found our slot, now skip all overloads
43 while (mo->method(i + 1).attributes() & QMetaMethod::Cloned)
44 ++i;
45 } else if (!(mo->method(i).attributes() & QMetaMethod::Cloned)) {
46 qWarning("QMetaObject::connectSlotsByName: No matching signal for %s", slot);
47 }
48 }
49 }
测试
看connectSlotsByName的实现,能够注意到如下几个地方:
第7行,取得o的全部子对象,在测试的代码里,QPushButton都设置了this为父对象,因此它们显然会在这个列表里出现
第8行,是一个遍历o的方法的循环,o的信号和槽就在其中
第11行,对于方法名称不是"on_"开头的方法跳过不处理,这也说明,若是你在一个QObject子类里定义了"on_"开头的槽的话,必定会被connectSlotsByName函数进行搜索匹配的操做的
第14行开始到33行,开始遍历o的全部的子对象,试图匹配到与槽名称以及信号名称相应的子对象。首先取出其objectName()与槽名称里的第一个‘_’和第二个‘_’作名称匹配。其次取出子对象的全部信号,与第二个‘_’以后部分作匹配。
若是匹配成功,则会执行36行的链接代码。链接成功的话,就会在38行break中断循环。
看到第5点,已经很明了了,对于同名的控件,connectSlotsByName只会链接子对象链表里的第一个对象的信号到槽上。
总结:
尽可能不要让QObject出现相同objectName的状况
若是同名connectSlotsByName只能给其中一个创建缺省的信号和槽的链接
若是出现大量编码建立大量控件的状况,最好是本身去创建信号和槽的链接,而不是依赖connectSlotsByName来作到这个工做。connectSlotsByName更适合的任务是与desinger配合完成缺省的信号和槽的链接。
其余:
在测试过程当中,曾经把ui->setupUi(this);放到了控件建立以前运行,结果运行时提示:
QMetaObject::connectSlotsByName: No matching signal for on_TestButton_clicked
从connectSlotsByName的代码能够看到这实际上执行的是第46行,若是在调试程序中遇到这样的信息,能够检查一下,是不是控件的objectName与你编写的槽里的objectName并不相符。ui