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

Q_INVOKABLE与QMetaObject::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 {
width: ; height:
Ellipse {
x: ; y: ; width: ; height:
color: "blue"
MouseArea {
anchors.fill: parent
// 调用C++中定义的randomColor方法
onClicked: parent.color = parent.randomColor()
}
}
}

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

二,跨线程编程中的使用

我们如何调用驻足在其他线程里的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( ), …)

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 = );
   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 = ; i < propertyCnt; ++ i )
{
QMetaProperty oneProperty = metaObj->property( i );
cout << " name: " << oneProperty.name();
cout << " type: " << QVariant::typeToName( oneProperty.type()) << "\n";
  }

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

得到注册的类成员函数

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

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

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

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

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

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

调用注册的函数

 
 int ret;
  MyClass newObj;
newObj.setMember1( );
newObj.setMember2( );
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)系统简介

Qt 反射,moc,Q_INVOKABLE的更多相关文章

  1. Qt 反射

    简介 本文主要讲解Qt是如何实现反射,以及一点点反射使用的小心得. 文章概览 Qt反射内幕小窥 详细内容 反射前期准备 得到注册的类成员变量 得到注册的类成员函数 访问类成员属性(get,set) 调 ...

  2. qt的moc,uic,rcc命令的使用

    qt是一个c++的界面库,其特点就是其源码可以跨平台编译,这样在写自己的小工具时可以方便地在windows,mac或linux环境下移植了.在windows下写c++程序当然选vs,在mac下写程序当 ...

  3. Why Does Qt Use Moc for Signals and Slots(QT官方的解释:GUI可以是动态的)

    GUIs are Dynamic C++ is a standarized, powerful and elaborate general-purpose language. It's the onl ...

  4. Qt笔记——MOC(莫克)

    moc 代表 Meta-Object Compiler,"元对象编译器".Qt 程序在交由标准编译器编译之前,先要使用 moc 分析 C++ 源文件. 假设它发如今一个头文件里包括 ...

  5. qt中moc的作用

    Qt 将源代码交给标准 C++ 编译器,如 gcc 之前,需要事先将这些扩展的语法去除掉.完成这一操作的就是 moc. moc 全称是 Meta-Object Compiler,也就是"元对 ...

  6. Verdigris: Qt without moc

    https://woboq.com/blog/verdigris-qt-without-moc.html https://github.com/woboq/verdigris

  7. QT跟VC++结合来进行插件的验证机制(遍历vtable,保证虚函数的个数一致,也可使用Q_INVOKABLE宏定义)

    由于最近公司要开发一个以C++插件机制为主的,主要有一个问题就是C++的二进制兼容性的问题.一旦类使用虚函数,只要随便改动下增删查改下头文件的虚函数,就会导致程序在跑的时候进行乱跳,因为这个时候exe ...

  8. 单独编译osgQt模块 Qt moc

    从alphapixel网站下载了OSG3.0.1VS2010x64版本的库,但是里面不包括osgQt模块,于是得自己编译 *************osgQtx64.zip工程文件可以去本博客园的“文 ...

  9. 如何才能学到Qt的精髓——信号槽之间的无关性,提供了绝佳的对象间通讯方式,QT的GUI全是自己的一套,并且完全开源,提供了一个绝好机会窥视gui具体实现

    姚冬,中老年程序员 叶韵.KY Xu.赵奋强 等人赞同 被邀请了很久了,一直在思考,今天终于下决心开始写回答. 这个问题的确是够大的,Qt的代码规模在整个开源世界里也是名列前茅的,这么大的项目其中的精 ...

随机推荐

  1. sublime_python编译_输出台中文为乱码

    Evernote Export sublime_python编译_输出台中文为乱码 创建时间: 2019-10-17 星期四 10:52 作者: 苏苏 标签: sublime, 乱码       问题 ...

  2. 三伏天里小试牛刀andriod 开发 #华为云·寻找黑马程序员#【华为云技术分享】

    2019年07月,北京,三伏天,好热啊.越热自己还越懒得动换(肉身给的信号),但是做为产品经理/交互设计师的,总想着思考些什么(灵魂上给的信号),或者是学习些什么,更有利于将来的职业发展吧,哈哈哈.工 ...

  3. 【sql笔记】oracle 循环

    =============================================== 2019/12/21_第1次修改                       ccb_warlock = ...

  4. Scala 系列(四)—— 数组 Array

    一.定长数组 在 Scala 中,如果你需要一个长度不变的数组,可以使用 Array.但需要注意以下两点: 在 Scala 中使用 (index) 而不是 [index] 来访问数组中的元素,因为访问 ...

  5. Java中守护线程的总结

    在Java中有两类线程:User Thread(用户线程).Daemon Thread(守护线程) 用个比较通俗的比如,任何一个守护线程都是整个JVM中所有非守护线程的保姆: 只要当前JVM实例中尚存 ...

  6. easy ui 弹框叠加问题

    1.框架用的是.net MVC,Index页面如下所示: @{ Layout = "~/Views/Shared/_CustomerLayout.cshtml"; ViewBag. ...

  7. 为什么UDP有时比TCP更有优势?

    随着网络技术飞速发展,网速已不再是传输的瓶颈,UDP协议以其简单.传输快的优势,在越来越多场景下取代了TCP.1.网速的提升给UDP稳定性提供可靠网络保障 CDN服务商Akamai(NASDAQ: A ...

  8. HTML学习摘要1

    在http://www.w3school.com.cn/ 学习前端知识,利用暑假,自主学习以拓展知识面 DAY 1 HTML 不是一种编程语言,而是一种标记语言 (markup language) 标 ...

  9. python SqlServer操作

    python连接微软的sql server数据库用的第三方模块叫做pymssql(document:http://www.pymssql.org/en/stable/index.html).在官方文档 ...

  10. VSCode 控制台面板输出乱码 字符编码问题 PHP --已解决

    首先上一张效果图,看看是不是你想要的效果. 第一步: 按F1,输入settings.json,添加 "code-runner.runInTerminal": true, 第二步:将 ...