小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

解讀QT信號(hào)與槽機(jī)制里 QMetaObject::connectSlotsByName(QObject *o)的源碼

 guitarhua 2012-02-14

介紹

connectSlotsByName 是一個(gè)QMetaObject類里的static函數(shù),其定義如下:

static void connectSlotsByName(QObject *o);

其作用是如其名稱一樣,用來將QObject *o里的子孫QObject的某些信號(hào)按照其objectName連接到o的槽上。

起因

為啥會(huì)對(duì)這個(gè)函數(shù)產(chǎn)生一探究竟的想法呢?——

既然是根據(jù)objectName來連接信號(hào)和槽,那么就有了幾個(gè)問題:

  1. 能不能對(duì)多個(gè)QObject設(shè)置同樣的objectName呢?
  2. 如果能,那么connectSlotsByName會(huì)連接多少個(gè)QObject的信號(hào)到指定的槽上呢?

測(cè)試結(jié)果

有了疑問,第一個(gè)應(yīng)該做的事情,當(dāng)然是編寫代碼進(jìn)行測(cè)試了。

在測(cè)試的主窗口類構(gòu)造函數(shù)在“ui->setupUi(this); ”語句前編寫如下代碼:

    for(int i=0;i<9;++i)
    {
        QPushButton 
*btn=new QPushButton(this);
        btn
->setObjectName(“TestButton”);
        qDebug(btn
->objectName().toStdString().c_str());
    }

    ui
->setupUi(this);

QMetaObject::connectSlotsByName()這個(gè)函數(shù)會(huì)在ui->setupUi(this);里被調(diào)用執(zhí)行。

然后在主窗口里增加下面的槽定義很代碼:

 

    void on_TestButton_clicked(bool bVal);

    
void MainWindow::on_TestButton_clicked(bool bVal)
    {
        QObject 
*obj=sender();
        qDebug(
"TestButton is clicked by %s!%d\n",obj->objectName().toStdString().c_str(),bVal);
    }

 

然后編譯運(yùn)行,結(jié)果出來了:

  1. 9個(gè)按鈕的objectName()都返回"TestButton"
  2. 只有第一個(gè)按鈕的clicked信號(hào)被連接到了on_TestButton_clicked槽上

第一個(gè)結(jié)論與我的猜想相符(后來看了QObject的源碼,也是比較簡(jiǎn)單的),第二個(gè)結(jié)論與我的猜想有點(diǎn)不同,我本來猜想,應(yīng)該是9個(gè)按鈕的 clicked信號(hào)應(yīng)該都可以連接到這個(gè)on_TestButton_clicked槽上的,但是卻只有第一個(gè)連接上了,這是為什么呢?

讓我們看看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的實(shí)現(xiàn),可以注意到以下幾個(gè)地方:

  1. 第7行,取得o的所有子對(duì)象,在測(cè)試的代碼里,QPushButton都設(shè)置了this為父對(duì)象,所以它們顯然會(huì)在這個(gè)列表里出現(xiàn)
  2. 第8行,是一個(gè)遍歷o的方法的循環(huán),o的信號(hào)和槽就在其中
  3. 第11行,對(duì)于方法名稱不是"on_"開頭的方法跳過不處理,這也說明,如果你在一個(gè)QObject子類里定義了"on_"開頭的槽的話,一定會(huì)被connectSlotsByName函數(shù)進(jìn)行搜索匹配的操作的
  4. 第14行開始到33行,開始遍歷o的所有的子對(duì)象,試圖匹配到與槽名稱以及信號(hào)名稱相應(yīng)的子對(duì)象。首先取出其objectName()與槽名稱里的第一個(gè)‘_’和第二個(gè)‘_’做名稱匹配。其次取出子對(duì)象的所有信號(hào),與第二個(gè)‘_’之后部分做匹配。
  5. 如果匹配成功,則會(huì)執(zhí)行36行的連接代碼。連接成功的話,就會(huì)在38行break中斷循環(huán)。

看到第5點(diǎn),已經(jīng)很明了了,對(duì)于同名的控件,connectSlotsByName只會(huì)連接子對(duì)象鏈表里的第一個(gè)對(duì)象的信號(hào)到槽上。

總結(jié)和其他

 

做個(gè)小小的總結(jié):

  1. 盡量不要讓QObject出現(xiàn)相同objectName的情況
  2. 如果同名connectSlotsByName只能給其中一個(gè)建立缺省的信號(hào)和槽的連接
  3. 如果出現(xiàn)大量編碼創(chuàng)建大量控件的情況,最好是自己去建立信號(hào)和槽的連接,而不是依賴connectSlotsByName來做到這個(gè)工作。connectSlotsByName更適合的任務(wù)是與desinger配合完成缺省的信號(hào)和槽的連接。

其他:

在測(cè)試過程中,曾經(jīng)把ui->setupUi(this);放到了控件創(chuàng)建之前運(yùn)行,結(jié)果運(yùn)行時(shí)提示:

QMetaObject::connectSlotsByName: No matching signal for on_TestButton_clicked

從connectSlotsByName的代碼可以看到這實(shí)際上執(zhí)行的是第46行,如果在調(diào)試程序中遇到這樣的信息,可以檢查一下,是否是控件的objectName與你編寫的槽里的objectName并不相符。

http://code.google.com/p/klsudoku

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多