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

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

  • 相关阅读:
    在SQLite中使用索引优化查询速度
    SQLite支持的SQL数据操作
    left (outer) join , right (outer) join, full (outer) join, (inner) join, cross join 区别
    深入理解Android内存管理原理(六)
    Merge Sorted Array
    Sort Colors
    Construct Binary Tree from Preorder and Inorder Traversal
    Binary Tree Postorder Traversal
    Symmetric Tree
    Rotate Image
  • 原文地址:https://www.cnblogs.com/chaoswong/p/3442778.html
Copyright © 2011-2022 走看看