zoukankan      html  css  js  c++  java
  • 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进行强制制定。

      

  • 相关阅读:
    批量新增百万条数据 十百万条数据
    sqlserver 组内排序
    EF ++属性会更新实体
    Entity Framework Core: A second operation started on this context before a previous operation completed
    abp Cannot access a disposed object. A common cause of this error is disposing
    abp xunit Can not register IHostingEnvironment. It should be a non-abstract class. If not, it should be registered before.”
    hangfire enqueued but not processing(hangfire 定时任务入队列但不执行)
    EF 更新实体 The instance of entity type 'BabyEvent' cannot be tracked because another instance
    datatable to entiy list 不支持可空类型和枚举类型
    webapi 设置不显示接口到swaggerUI
  • 原文地址:https://www.cnblogs.com/zwj412/p/10176260.html
Copyright © 2011-2022 走看看