QMetaObject::connectSlotsByName 总结

《《总结之一》

===================================================================================================

查看Qt4的一些示例项目的时候,使用设计器打开其UI文件,在文件中竟然找不到signal和slot的连接。但是最终的程序,slot却又能准确的响应信号。打开通过ui文件自动生成的c++文件,其中也找不到connect语句,到底是怎么一回事?
  
  经过逐语句的分析。终于发现连接的原因就在于setUi函数的最后一句
  
  QMetaObject::connectSlotsByName(MainWindow);
  
   找到该静态函数
  
  void QMetaObject::connectSlotsByName(QObject *o)
  {
   if (!o)
   return;
   const QMetaObject *mo = o->metaObject();
   Q_ASSERT(mo);
   const QObjectList list = qFindChildren(o, QString());
   for (int i = 0; i < mo->methodCount(); ++i) {
  
  
   const char *slot = mo->method(i).signature();
   Q_ASSERT(slot);
  
  //以下一行用来判断slot的前三位是否是on_,如果不是,就跳过这个方法。
   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();
  
  //要求slot跳过前3位(on_)后,接下来的子字符串和子对象名相同,并且接着该子字符串又是一个_
  
  //如果达不到这个要求,continue
   if (!len || qstrncmp(slot + 3, objName.data(), len) || slot[len+3] != ‘_‘)
   continue;
   const QMetaObject *smo = co->metaObject();
   int sigIndex = smo->indexOfMethod(slot + len + 4);
   if (sigIndex < 0) { // search for compatible signals
   int slotlen = qstrlen(slot + len + 4) - 1;
  
  //搜索该子对象所能引发的信号
   for (int k = 0; k < co->metaObject()->methodCount(); ++k) {
  //方法类型如果符合要求
  
   if (smo->method(k).methodType() != QMetaMethod::Signal)
   continue;
  
  //如果slot最后的子字符串和信号名相同
  
   if (!qstrncmp(smo->method(k).signature(), slot + len + 4, slotlen)) {
   sigIndex = k;
   break;
   }
   }
   }
   if (sigIndex < 0)
   continue;
  
  //连接操作
   if (QMetaObject::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);
   }
   }
  }
  
  得出此结论:自动生成的文件中,该函数总会存在setUi函数的最后一句。
  
  该函数的作用就是寻找setUi的唯一指针参数MainWindow所指向对象的成员函数,
  
  该成员函数的名字如果满足以下条件,就做连接操作。
  
  函数名规则:on_子对象名_信号名
  
  函数签名(即返回值与参数要符合slot要求)
  
  所以,我们可以这样做:在qt设计器中添加按纽或者菜单项或者按纽项后,不用在设计器中手动做连接操作。
  
  我们只要在主窗口类中添加符合条件的成员函数即可。
  
  函数名规则:on_子对象名_信号名
  
  函数签名(即返回值与参数要符合slot要求)
  
  例如:
  
  在设计器中添加一个菜单项,其对应的action为actionNew
  
  那么在主窗口类中添加以下的函数
  
  public slots:
  
   void on_actionNew_triggered();
  
  当切换这个菜单时,会自动执行上面的成员函数。

《《总结之二》

===================================================================================================

别人代码看到void on_MyWidget_slotTest();

就郁闷了,没看到他代码里有connect 却能把信号和槽可以连接起来。

今日回顾书本发现该函所的nb之处。

QMetaObject::connectSlotsByName(QObject * object)将递归的搜寻传入的Qt对象object的所有子对象,并把所有匹配的子对象的信号关联到object对象的符合下列规则的槽函数void on_<窗口部件名称>_<信号名称>(<信号参数>)

如果窗口部件已经提供信号Qt可以自动关联。

《《总结之三》

===================================================================================================

void QMetaObject::connectSlotsByName(QObject *o)
{
    if (!o)
        return;  //如果空,退出
    const QMetaObject *mo = o->metaObject();
    Q_ASSERT(mo); //如果不是一个meta Object
    const QObjectList list = qFindChildren<QObject *>(o, QString()); //查找子对象,放入list
    for (int i = 0; i < mo->methodCount(); ++i) {  //对于mo的所有方法
        const char *slot = mo->method(i).signature(); //取出slot 的名字字符串
        Q_ASSERT(slot);
        if (slot[0] != ‘o‘ || slot[1] != ‘n‘ || slot[2] != ‘_‘)
            continue;  // 如果不是以on_开头,就下次继续
        bool foundIt = false; //初始化foundIt 为假, 这是找到标志
        for(int j = 0; j < list.count(); ++j) {  //对所有的子对象,去找它的signal
            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; // 如果objName对不上on_后面的那个字符串的话,说明找错了子对象,继续下次
            const QMetaObject *smo = co->metaObject();
            int sigIndex = smo->indexOfMethod(slot + len + 4); //找到子对象的signal偏移
            if (sigIndex < 0) { // search for compatible signals
                int slotlen = qstrlen(slot + len + 4) - 1;
                for (int k = 0; k < co->metaObject()->methodCount(); ++k) {
                    if (smo->method(k).methodType() != QMetaMethod::Signal)
                        continue;

if (!qstrncmp(smo->method(k).signature(), slot + len + 4, slotlen)) {
                        sigIndex = k;
                        break;
                    }
                }
            }
            if (sigIndex < 0)
                continue;
            if (QMetaObject::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);
        }
    }
}

经过我几个小时的艰苦探索,哈哈..终于搞定了,现在给大家分享一下吧...         

关键的关键是对象的 "父子关系" !! 必须让发出signal的对象是slot类的对象的儿子 !

这个很简单,只要先  m->setParent(this); // 其中,m是发出signal的对象,this是有slot的对象..

最后不要忘了, QMetaObject::connectSlotsByName(this); 哦,呵呵       

一切就这么简单,开始享受自动连接的快乐吧!!^_^  写个相应的on_xxxx_xxxx就可以了,再也不要一大堆的connect了...哈哈,,再见啦!

时间: 2024-08-14 16:33:51

QMetaObject::connectSlotsByName 总结的相关文章

qt QMetaObject::connectSlotsByName()自动关联失效问题解决

自己编写qt程序的时候,想使用qt on_objectName_signalName()命名规则自动关联信号和槽,老是发现失效.多方求解,答案事实上很简单就是没有理解objectName的含义. on_objectName_signalName(signalParameters):仔细看好是objectName而不是变量名,一个控件的变量名和objectName是不同的.需要这样改:    pushButton = new QPushButton(tr("ok"));    pushB

Qt 静态函数QMetaObject::connectSlotsByName(QObject * object)按命名规则自动connect,不需要手动connect

看别人代码看到void on_MyWidget_slotTest(); 就郁闷了,没看到他代码里有connect 却能把信号和槽可以连接起来. 今日回顾书本发现该函所的nb之处. QMetaObject::connectSlotsByName(QObject * object)将递归的搜寻传入的Qt对象object的所有子对象,并把所有匹配的子对象的信号关联到object对象的符合下列规则的槽函数void on_<窗口部件名称>_<信号名称>(<信号参数>) 如果窗口部

关于Qt MetaObject connectSlotsByName

QMetaObject::connectSlotsByName(QObject * object)将递归的搜寻传入的Qt对象object的所有子对象,并把所有匹配的子对象的信号关联到object对象的符合下列规则的槽函数void on_<窗口部件名称>_<信号名称>(<信号参数>) 注意: 1,设定父子关系,发送信号的对象必须是槽函数对象的子类,及函数参数 object的子类 2. 必须设置ObjectName, 变量名称不一定是对象名称(objectName) MyC

PYQT设计无边框窗体

#UI.py,通过UI设计师制作后直接转换为UI.py脚本 # -*- coding: utf-8 -*-from PyQt4 import QtCore, QtGui try:    _fromUtf8 = QtCore.QString.fromUtf8except AttributeError:    _fromUtf8 = lambda s: s class Ui_Form(object):    def setupUi(self, Form):        Form.setObject

QT基础(一) ui类设计和使用

用designer设计的*.ui文件可以通过uic工具转换为*.h文件(在编译时也会自动生成这样一个ui_*.h文件),有了这个.h文件就可以直接按照纯C++的方式对其中的类进行调用.ui文件的使用就是利用默认工具uic自动产生一个类,然后用该类的setui函数加载界面到相应的对象上.       .ui文件的使用有三种形式:第一种是直接使用,第二种是定义一个新类,声明一个ui子对象,利用该对象来加载界面,第三种是将ui作为基类派生新的类. 借用一个例程分析如下: 工程及界面          

python窗体——pyqt初体验

连续两周留作业要写ftp的作业,从第一周就想实现一个窗体版本的,但是时间实在太短,qt零基础选手表示压力很大,幸好又延长了一周时间,所以也就有了今天这篇文章...只是为了介绍一些速成的方法,还有初学者会遇到的问题... 这里先介绍一个安装连接,一条龙服务,各种安装配置在这里都找得到:http://blog.sina.com.cn/s/blog_4c18e3160101a12g.html 什么是pyqt? 简而言之,qt是一个开发窗体程序的模块,原本是是C++的库,PyQt是Python的移植版本

[转]Qt中ui文件的使用

用designer设计的*.ui文件可以通过uic工具转换为*.h文件(在编译时也会自动生成这样一个ui_*.h文件),有了这个.h文件就可以直接按照纯C++的方式对其中的类进行调用.ui文件的使用就是利用默认工具uic自动产生一个类,然后用该类的setui函数加载界面到相应的对象上.       .ui文件的使用有三种形式:第一种是直接使用,第二种是定义一个新类,声明一个ui子对象,利用该对象来加载界面,第三种是将ui作为基类派生新的类. 借用一个例程分析如下: 工程及界面          

python+QT designer 做图形化界面EXE程序

1.安装python 2.安装QT designer 或QT creator 3.打开QT designer 绘制你想要的图形化界面 类似这样 之后将文件保存,以ui后缀形式保存 4.下载安装pyside 直接easy_install 或pip安装 可能会保存,我安装的时候,提示 msvc 版本问题 查看许多国外论坛后,可以选择,pyside网站下载 对应Python版本的 whl安装包,下载成功之后,进入对应目录路径,直接 pip install  *.whl    *为包名 安装成功 5.将

python3.5 + PyQt5 +Eric6 实现的一个计算器

目前可以实现简单的计算.计算前请重置,设计的时候默认数字是0,学了半天就做出来个这么个结果,bug不少. python3.5 + PyQt5 +Eric6 在windows7 32位系统可以完美运行 计算器,简单学了半天就画个图实现的存在bug,部分按钮还未实现,后续优化. 代码结构如图: 1 jisuan.py 2 import re 3 #匹配整数或小数的乘除法,包括了开头存在减号的情况 4 mul_div=re.compile("(-?\d+)(\.\d+)?(\*|/)(-?\d+)(\