QPushButton槽函数触发两次的问题

  以前经常使用qt creator界面管理直接跳转到槽函数没发现这个问题,今天手动写了个槽函数发现按键会触发两次。根据网上的说法是按键会自动连接一个槽函数,如果我们手动添加的槽函数命名规则符合槽函数的命名规则的话,此时就会出现触发两次的问题。

  带着这个疑问,我们去代码里找答案。首先是在界面自动生成的ui_mainwindow.h(由你按键所在的界面决定),我们找到了自动建立槽函数连接的代码

       retranslateUi(MainWindow);
       QMetaObject::connectSlotsByName(MainWindow);

  继续跟踪发现这个系统函数connectSlotsByName是定义在qobject中,切换过去发现文件头有如下声明

    \section1 Auto-Connection

    Qt's meta-object system provides a mechanism to automatically connect
    signals and slots between QObject subclasses and their children. As long
    as objects are defined with suitable object names, and slots follow a
    simple naming convention, this connection can be performed at run-time
    by the QMetaObject::connectSlotsByName() function.

  大意就是我们之前说的如果槽函数的命名满足一定形式的简单规则,那么这个函数就会将信号和槽自动连接起来,跟踪源代码我们看下规则到底是怎样的

 

 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); } } }

大概看了下(有兴趣的可自行研究),要满足如图上红色标志处的如下两个规则
1、首先是要以on_开头
2、其次,要以“_”+行为结束,例如_clicked

了解这个后我们再回到之前的问题,假如一个按键QPushButton,如果我们定义一个槽函数on_QPushButton_clicked(void)的话,此时不需要额外进行connect()操作,程序编译时会自动将槽函数连接起来。
而这次如果我们额外进行connect操作的话,就会出现槽函数触发两次的情况了。
解决的办法很简单,手动连接时槽函数名字规避命名规则就行了,如上我们定义成QPushButton_clicked(void),或者在connect时使用qt::uniqueconnection进行强制制定。

  

 

posted @ 2018-12-25 20:26  碧哈姆特  阅读(2189)  评论(1编辑  收藏  举报