• Qt 反射,moc,Q_INVOKABLE


    使用Q_INVOKABLE来修饰成员函数,目的在于被修饰的成员函数能够被元对象系统所唤起

    Q_INVOKABLEQMetaObject::invokeMethod均由元对象系统唤起。这一机制在Qt C++/QML混合编程,跨线程编程,Qt Service Framework 以及 Qt/ HTML5混合编程以及里广泛使用。

    一,Qt C++/QML混合编程

    QML中调用C++方法借助了Qt元对象系统。考虑在QML中使用Qt C++定义的方法,如下代码所示

    mport Qt 4.7   
    import Shapes 5.0   //自定义模块  
    Item {   
         300; height: 200  
        Ellipse {   
             x: 50; y: 35;  200; height: 100   
            color: "blue"   
             MouseArea {   
                anchors.fill: parent  
                // 调用C++中定义的randomColor方法   
                onClicked: parent.color = parent.randomColor()    
            }   
        }  
    }  

    为了让上述QML代码成功的调用下面这段代码定义的randomColor()函数,最为关键的一点见randomColor方法用Q_INVOKABLE 修饰。

    #include <QDeclarativeItem >  
    class EllipseItem : public QDeclarativeItem   
    {   
        Q_OBJECT   
    publicQ_INVOKABLE QColor randomColor() const;  
          …  
    }  
    二,跨线程编程中的使用

    我们如何调用驻足在其他线程里的QObject方法呢?Qt提供了一种非常友好而且干净的解决方案:向事件队列post一个事件,事件的处理将以调用我们所感兴趣的方法为主(当然这需要线程有一个正在运行的事件循环)。而触发机制的实现是由moc提供的内省方法实现的因此,只有信号、槽以及被标记成Q_INVOKABLE的方法才能够被其它线程所触发调用。如果你不想通过跨线程的信号、槽这一方法来实现调用驻足在其他线程里的QObject方法。另一选择就是将方法声明为Q_INVOKABLE,并且在另一线程中用invokeMethod唤起。

    QMetaObject::invokeMethod

    静态方法QMetaObject::invokeMethod() 的定义如下:

    bool QMetaObject::invokeMethod ( QObject * obj, const char * member,Qt::ConnectionType type,  
    QGenericReturnArgument ret, QGenericArgument val0 = QGenericArgument( 0 ), …)  

    invokeMethod的用法为,尝试调用对象obj的方法member(注意member可以为信号或者是槽),如果member可以被调用,则返回真,否则返回假。QMetaObject::invokeMethod可以是异步调用,也可以是同步调用。这取决与它的连接方式Qt::ConnectionType type。如果type为Qt::DirectConnection,则为同步调用,若为Qt::QueuedConnection,则为异步调用。例如:

    QMetaObject::invokeMethod(object, "methodName",   
    Qt::QueuedConnection,   
    Q_ARG(type1, arg1),   
    Q_ARG(type2, arg2));  

    原文:https://blog.csdn.net/txgc1009/article/details/6630928

    Qt反射

    Qt反射机制是基于moc(meta object compiler)实现的,在这里多插一句(可以说Qt所有C++没有的特性,几乎都和这个有关系)。但是需要注意的是Qt提供的反射式基本的反射,不支持类的反射,这个与Java,C#还是有差别的。

    moc讲解

    通常C++的编译过程为

    预处理->编译->链接->运行

    Qt编译的过程中,有一个moc的过程,在Qt工程构建过程中的qmake其实就是干这个事的。moc->预处理->编译->链接->运行

    在moc过程中,需要处理的事情如下:

    1、 识别一些特殊的宏Q_OBJECT、Q_PROPERTY、Q_INVOKABLE。。。; 如果碰到这些关键字,Qt自然就会去生成对应的moc文件。

    2、 slot,signal自然也是如此。

    3、 uidesigner,同样也是在这个阶段处理的;

    详细内容

    反射前期准备

    1、 首先得继承于Q_Object,同时需要在class中加入Q_OBJECT,但是Q_Object的构造函数默认是私有的不让继承。

    在类中直接使用Q_GADGET也可以实现反射,。。。据说只能实现部分功能,目前我只实现到能遍历成员属性,函数,但是不能访问其中的值。

    这个过程其实就是定义QMetaObject的过程,具体见Qt源码

    2、 注册类成员变量需要使用Q_PROPERTY

    Q_PROPERTY( type member READ get WRITE set) 其中READ,WRITE是关键字

    Type表示成员的类型(不支持自定义类型,对Qt很多基本类型都支持);

    Member代表你给该成员另外起的名字,可以和变量名不同;get,set就是自己在C++函数里面定义的基本的访问函数名,不需要写参数。直接上代码:

    3、 注册类成员函数

    如果你希望这个函数能够被反射,那么很简单,只需要在类的函数声明前加入Q_INVOKABLE关键字

    例如Q_INVOKABLE int func( QString flag );

    #include <QObject>
       class MyClass : public QObject
       {
        Q_OBJECT
        Q_PROPERTY(int Member1 READ Member1 WRITE setMember1 )
        Q_PROPERTY(int Member2 READ Member2 WRITE setMember2 )
        Q_PROPERTY(QString MEMBER3 READ Member3 WRITE setMember3 )
       public:
        explicit MyClass(QObject *parent = 0);
       signals:
       public slots:
       public:
        Q_INVOKABLE int Member1();
        Q_INVOKABLE int Member2();
        Q_INVOKABLE QString Member3();
        Q_INVOKABLE void setMember1( int mem1 );
        Q_INVOKABLE void setMember2( int mem2 );
        Q_INVOKABLE void setMember3( const QString& mem3 );
        Q_INVOKABLE int func( QString flag );
       private:
        int m_member1;
        int m_member2;
        QString m_member3;
       };

    得到注册的类成员变量

      MyClass theObj;
     const QMetaObject* metaObj = theObj.metaObject();
     //1.遍历类的属性
     int propertyCnt = metaObj->propertyCount();
     for ( int i = 0; i < propertyCnt; ++ i )
     {
     QMetaProperty oneProperty = metaObj->property( i );
     cout << " name: " << oneProperty.name();
     cout << " type: " << QVariant::typeToName( oneProperty.type()) << "
    ";
      }

    主要思路就是得到其元对象,得到其元属性,然后就能得到你需要的信息,具体的访问函数有name,type,需要注意的是得到的type是枚举值,还在Qt提供了typeToName的函数,你可以得到想要的(例如不是空洞的2,而是”int”)。

    得到注册的类成员函数

    //2.遍历类的函数成员
     int methodCnt = metaObj->methodCount();
     for ( int idx = 0; idx < methodCnt; ++ idx )
     {
     QMetaMethod oneMethod = metaObj->method( idx );
     cout << "--------begin-------" << "
    ";
     cout << " typeName: " << oneMethod.typeName() << "
    ";
     cout << " signature: " << oneMethod.signature() << "
    ";
     cout << " methodType: " << oneMethod.methodType() << "
    ";
     cout << "--------end---------" << "
    ";
      }

    和遍历类属性一致,其实就是根据元对象,得到元函数;

    其中typeName代表返回类型,signature只的是函数的原貌,methodType代表函数的类型,在Qt中分为三类(槽,信号,普通函数)。

    访问类成员属性(get,set)

    //3.使用反射
     cout << "-------test property-----------" << "
    ";
     MyClass newObj;
     newObj.setProperty("Member1", 66);
     cout << newObj.property( "Member1" ).toString().toStdString() << "
    ";
     cout << newObj.Member1() << "
    ";
     cout << "--------end----------" << "
    ";

    在这里使用的是QObject的property() 和setProperty方法,来访问成员信息。但是对于使用Q_GADGET宏的类,是不能使用这个方法的,还在寻找解决方法,基本思路当然是重写。

    调用注册的函数

     
     int ret;
      MyClass newObj;
     newObj.setMember1( 20 );
     newObj.setMember2( 50 );
     QMetaObject::invokeMethod( &newObj, "func", Qt::DirectConnection,
     Q_RETURN_ARG(int, ret ),
     Q_ARG(QString, "+"));

    //普通函数的调用

    在MyClass中,我们定义了int func( QString flag );这个函数,利用反射的调用方式如上,主要是理解invokeMethod的用法,其中Qt::DirectConnection是函数的执行方式,分为(异步和同步),Q_RETURN_ARG是返回参数,Q_ARG是传入参数,需要按函数声明中参数的顺序依次传入,Qt最多支持9个参数,对于一般的应用没有问题。还有疑问,请移步具见Qt强大的帮助文档。

    反射的应用

    反射反射,就我目前的认知水平来看,通过使用字符串,来实现函数的通用化调用,例如你可以利用反射把很多函数放置到数组中,实现一次遍历,全部调用。

    目前我见到的大多是利用反射来操作数据库,例如hibernate,其实可以利用Qt的反射,快速实现所谓的hibernate,(最近自己独立实现了一套,很方便)。

    Qt的元对象(Meta-Object)系统简介

  • 相关阅读:
    python实现七段数码管显示
    词频统计实例
    分形几何中科赫雪花的绘制
    脚本实现自动化绘制
    Android查看数据库方法及工具(转)
    2011年度总结
    Bad NPObject as private data 解决方案
    LINQ学习之旅——LINQ TO SQL继承支持(转载)
    我记录开源系统1.6源码解析(一)
    2011年度总结
  • 原文地址:https://www.cnblogs.com/xiangtingshen/p/11387911.html
Copyright © 2020-2023  润新知