Q_INVOKABLE与invokeMethod用法全解

系统 4384 0



Qt/Qt Quick宏浅议 一文中,我们将介绍Qt中经常使用的几个宏: Q_OBJECT, SIGNAL与SLOT, Q_SIGNALS 与 Q_SLOTS, Q_EMIT ,Q_INVOKABLE, Q_PROPERTY。相比其他宏,Q_INVOKABLE 显得更加神秘,但Q_INVOKABLE的理解与使用变得越来越重要。本文将围绕Q_INVOKABLE以及相对应的invokeMethod展开讨论。

Q_INVOKABLE

#define Q_INVOKABLE

重新回顾一下Q_INVOKABLE的定义,它在$QTDIR/src/corelib/kernel/qobjectdefs.h 中,简单被define,目的在于让moc识别。

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

QMetaObject::invokeMethod

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

    1. bool QMetaObject::invokeMethod(QObject*obj, const char *member,Qt::ConnectionTypetype,
    2. QGenericReturnArgumentret,QGenericArgumentval0=QGenericArgument(0),…)

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

    1. QMetaObject::invokeMethod(object, "methodName" ,
    2. Qt::QueuedConnection,
    3. Q_ARG(type1,arg1),
    4. Q_ARG(type2,arg2));

上述调用为异步调用。请注意,因为上面所示的参数需要被在构建事件时进行硬拷贝,参数的自定义型别所对应的类需要提供一个共有的构造函数、析构函数以及拷贝构造函数。而且必须使用注册Qt型别系统所提供的qRegisterMetaType() 方法来注册这一自定义型别。

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

Qt C++/QML混合编程

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

  1. importQt4.7
  2. importShapes5.0 //自定义模块
  3. Item{
  4. width:300;height:200
  5. Ellipse{
  6. x:50;y:35;width:200;height:100
  7. color: "blue"
  8. MouseArea{
  9. anchors.fill:parent
  10. //调用C++中定义的randomColor方法
  11. onClicked:parent.color=parent.randomColor()
  12. }
  13. }
  14. }

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

  1. #include<QDeclarativeItem>
  2. class EllipseItem: public QDeclarativeItem
  3. {
  4. Q_OBJECT
  5. public
  6. Q_INVOKABLEQColorrandomColor() const ;

更多细节,请参看我的另一篇博文: QML与C++混合编程使用

在跨线程编程中的使用

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

更多细节,译文 事件循环与线程

Qt Service Framework

Qt服务框架是Qt Mobility 1.0.2版本推出的,一个服务(service)是一个独立的组件提供给客户端(client)定义好的操作。客户端可以通过服务的名称,版本号和服务的对象提供的接口来查找服务。 查找到服务后,框架启动服务并返回一个指针。

服务通过插件(plug-ins)来实现。为了避免客户端依赖某个具体的库,服务必须继承自QObject。这样 QMetaObject 系统可以用来提供动态发现和唤醒服务的能力。要使QmetaObject机制充分的工作,服务必须满足,其所有的方法都是通过 signal,slot,property 或 invokable method Q_INVOKEBLE 来实现

其中,最常见的与servicer交互的方法如下:

      
  1. QServiceManagermanager;QObject*storage;
  2. storage=manager.loadInterface( "com.nokia.qt.examples.FileStorage" ); if (storage)QMetaObject::invokeMethod(storage, "deleteFile" ,Q_ARG(QString, "/tmp/readme.txt" ));
      上面的代码通过service的元对象提供的invokeMethod方法,调用文件存储对象的deleteFile() 方法。客户端不需要知道对象的类型,因此也没有链接到具体的service库。 当然在服务端的deleteFile方法,一定要被标记为
      
        Q_INVOKEBLE,
      
      才能够被元对象系统识别
    

Qt服务框架的一个亮点是它支持 跨进程通信 ,服务可以接受远程进程。在服务管理器上注册后 进程通过signal,slot, invokable method 和property来通信,就像本地对象一样。服务可以设定为在客户端间共享,或针对一个客户端。 请注意 ,在Qt服务框架推出之前,信号、槽以及invokable method仅支持跨线程。 下图是跨进成的服务/客户段通信示意图(图片来自诺基亚论坛)。这里我们可以清楚的看到, invokable method Q_INVOKEBLE 是跨进城、跨线程对象之间通信的重要利器。

serivceFramework

有关Qt Service Framework的更多讨论和用例,请参见 Qt Service Framework文档

请尊重原创作品和译文。转载请保持文章完整性,并以超链接形式注明原始作者 地址 http://blog.csdn.net/changsheng230 ,方便其他朋友提问和指正。


Qt/Qt Quick宏浅议 一文中,我们将介绍Qt中经常使用的几个宏: Q_OBJECT, SIGNAL与SLOT, Q_SIGNALS 与 Q_SLOTS, Q_EMIT ,Q_INVOKABLE, Q_PROPERTY。相比其他宏,Q_INVOKABLE 显得更加神秘,但Q_INVOKABLE的理解与使用变得越来越重要。本文将围绕Q_INVOKABLE以及相对应的invokeMethod展开讨论。

Q_INVOKABLE

#define Q_INVOKABLE

重新回顾一下Q_INVOKABLE的定义,它在$QTDIR/src/corelib/kernel/qobjectdefs.h 中,简单被define,目的在于让moc识别。

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

QMetaObject::invokeMethod

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

    1. bool QMetaObject::invokeMethod(QObject*obj, const char *member,Qt::ConnectionTypetype,
    2. QGenericReturnArgumentret,QGenericArgumentval0=QGenericArgument(0),…)

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

    1. QMetaObject::invokeMethod(object, "methodName" ,
    2. Qt::QueuedConnection,
    3. Q_ARG(type1,arg1),
    4. Q_ARG(type2,arg2));

上述调用为异步调用。请注意,因为上面所示的参数需要被在构建事件时进行硬拷贝,参数的自定义型别所对应的类需要提供一个共有的构造函数、析构函数以及拷贝构造函数。而且必须使用注册Qt型别系统所提供的qRegisterMetaType() 方法来注册这一自定义型别。

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

Qt C++/QML混合编程

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

  1. importQt4.7
  2. importShapes5.0 //自定义模块
  3. Item{
  4. width:300;height:200
  5. Ellipse{
  6. x:50;y:35;width:200;height:100
  7. color: "blue"
  8. MouseArea{
  9. anchors.fill:parent
  10. //调用C++中定义的randomColor方法
  11. onClicked:parent.color=parent.randomColor()
  12. }
  13. }
  14. }

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

  1. #include<QDeclarativeItem>
  2. class EllipseItem: public QDeclarativeItem
  3. {
  4. Q_OBJECT
  5. public
  6. Q_INVOKABLEQColorrandomColor() const ;

更多细节,请参看我的另一篇博文: QML与C++混合编程使用

在跨线程编程中的使用

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

更多细节,译文 事件循环与线程

Qt Service Framework

Qt服务框架是Qt Mobility 1.0.2版本推出的,一个服务(service)是一个独立的组件提供给客户端(client)定义好的操作。客户端可以通过服务的名称,版本号和服务的对象提供的接口来查找服务。 查找到服务后,框架启动服务并返回一个指针。

服务通过插件(plug-ins)来实现。为了避免客户端依赖某个具体的库,服务必须继承自QObject。这样 QMetaObject 系统可以用来提供动态发现和唤醒服务的能力。要使QmetaObject机制充分的工作,服务必须满足,其所有的方法都是通过 signal,slot,property 或 invokable method Q_INVOKEBLE 来实现

其中,最常见的与servicer交互的方法如下:

    
  1. QServiceManagermanager;QObject*storage;
  2. storage=manager.loadInterface( "com.nokia.qt.examples.FileStorage" ); if (storage)QMetaObject::invokeMethod(storage, "deleteFile" ,Q_ARG(QString, "/tmp/readme.txt" ));
    上面的代码通过service的元对象提供的invokeMethod方法,调用文件存储对象的deleteFile() 方法。客户端不需要知道对象的类型,因此也没有链接到具体的service库。 当然在服务端的deleteFile方法,一定要被标记为
    
      Q_INVOKEBLE,
    
    才能够被元对象系统识别
  

Qt服务框架的一个亮点是它支持 跨进程通信 ,服务可以接受远程进程。在服务管理器上注册后 进程通过signal,slot, invokable method 和property来通信,就像本地对象一样。服务可以设定为在客户端间共享,或针对一个客户端。 请注意 ,在Qt服务框架推出之前,信号、槽以及invokable method仅支持跨线程。 下图是跨进成的服务/客户段通信示意图(图片来自诺基亚论坛)。这里我们可以清楚的看到, invokable method Q_INVOKEBLE 是跨进城、跨线程对象之间通信的重要利器。

serivceFramework

有关Qt Service Framework的更多讨论和用例,请参见 Qt Service Framework文档

请尊重原创作品和译文。转载请保持文章完整性,并以超链接形式注明原始作者 地址 http://blog.csdn.net/changsheng230 ,方便其他朋友提问和指正。

Q_INVOKABLE与invokeMethod用法全解


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论