zoukankan      html  css  js  c++  java
  • Qt里的slot

    昨天出了一个小bug, 一直调都没调出来, 今天仔细看了下, 发现出错的原因了.

    我在用osgEarth的时候, 用到一个类MapCatalogWidget, 觉得它不够用, 就把这个类给改了下, 添加了个slot:

    public slots:
        void addViewpoint(Viewpoint& vp);

    这里由于MapCatalogWidget类自己已经添加了命名空间的引用, 所以想当然的在这里就没有使用 osgEarth::Viewpoint 这样的方式.

    添加信号, 槽:

    connect(manip, SIGNAL(viewpoint(osgEarth::Viewpoint&)),
            vpCatalog, SLOT(addViewpoint(osgEarth::Viewpoint&)));

    结果添加完后, 怎么也不响应, 而且输出窗口出还出现这么一句话:

    Object::connect: No such slot osgEarth::QtGui::MapCatalogWidget::addViewpoint(osgEarth::Viewpoint&)

    明明自己写了啊, 怎么就找不着呢....

    经过分析, 觉得应该是出在moc处理slot上, 查看了下moc_MapCatalogWidget.cpp文件, 就发现了问题:

    static const char qt_meta_stringdata_osgEarth__QtGui__MapCatalogWidget[] = {
    "osgEarth::QtGui::MapCatalogWidget"
    "onMapChanged()onSelectionChanged()"
    "item,colonTreeItemDoubleClicked(QTreeWidgetItem*,int)"
    "onTreeItemChanged(QTreeWidgetItem*,int)"
    "onTreeSelectionChanged()pos"
    "onTreeNodeRClick(QPoint)editModel()"
    "vpaddViewpoint(Viewpoint&)delViewpoint()"
    };

     

    void osgEarth::QtGui::MapCatalogWidget::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
    {
      if (_c == QMetaObject::InvokeMetaMethod) {
        Q_ASSERT(staticMetaObject.cast(_o));
        MapCatalogWidget *_t = static_cast<MapCatalogWidget *>(_o);
        switch (_id) {
          case 0: _t->onMapChanged(); break;
          case 1: _t->onSelectionChanged(); break;
          case 2: _t->onTreeItemDoubleClicked((*reinterpret_cast< QTreeWidgetItem*(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break;
          case 3: _t->onTreeItemChanged((*reinterpret_cast< QTreeWidgetItem*(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break;
          case 4: _t->onTreeSelectionChanged(); break;
          case 5: _t->onTreeNodeRClick((*reinterpret_cast< const QPoint(*)>(_a[1]))); break;
          case 6: _t->editModel(); break;
          case 7: _t->addViewpoint((*reinterpret_cast< Viewpoint(*)>(_a[1]))); break;
          case 8: _t->delViewpoint(); break;
          default: ;
        }
      }
    }

    可以看出这里moc解析slot后, 会得到这样一组字符串数组, 然后用数组中的"特殊"字符串的索引来做case, 以映射到对应的函数中.

    这里之所以说是特殊字符串, 你可以仔细看看那个字符串数组, 它是分为两个部分, 用""分隔开, 第一部分是类名, 第二部分是函数名, 这里函数如果带参数的话, 参数是放在函数名前的, 函数名和参数名都用""来分隔的 (这里真心佩服qt的团队, 这种办法也想得出来.....).

    看完这里的代码, 其实connect函数干的事情应该也能分析出个大概:

    1. 把SIGNAL和SLOT宏的参数转换成字符串

    2. 在实际调用的时候, Qt会将发出的信息, 转换得到匹配的槽

    3. 再转到槽类中, 用字符串匹配到对应的函数来执行.

    connect(manip, SIGNAL(viewpoint(Viewpoint&)),
            vpCatalog, SLOT(addViewpoint(Viewpoint&)));

    这里要注意一下, 两个域约束符号要去都要去, 否则运行时, qt会在输出窗口中提示你:

    QObject::connect: Incompatible sender/receiver arguments
            UIManipulator::viewpoint(osgEarth::Viewpoint&) --> osgEarth::QtGui::MapCatalogWidget::addViewpoint(Viewpoint&)

    问题了解了, 解决就比较简单了!

    我这里只要把MapcatalogWidget中的槽函数声明加上域约束符就OK了.

    public slots:
        void addViewpoint(osgEarth::Viewpoint& vp);

    希望能帮上有同样问题的朋友.

  • 相关阅读:
    EUI库
    EUI库
    EUI库
    EUI库
    EUI库
    EUI库
    EUI库
    EUI库
    EUI库
    EUI库
  • 原文地址:https://www.cnblogs.com/chaoswong/p/3442778.html
Copyright © 2011-2022 走看看