QT实现同步异步转换QMetaObject::invokeMethod

摘要

如果用QT书写GUI的话,为不影响主界面的工作(不卡主界面),实现工作线程和GUI线程的调度,QT提供了很好的方法——QMetaObject::invokeMethod,并针对该函数提供了多个重载。本文将常用功能记录如下。

背景

在客户端编程中,尤其是针对复杂的客户端场景下,尤其是GUI和工作线程之间需要交互时,经常涉及到异步到同步之间的转换,包括但不限于如下的场景:

http请求
websocket请求
调用第三方sdk时,第三方返回给出的回调需要GUI响应

解决方法

如果用QT书写GUI的话,QT提供了很好的方法——QMetaObject::invokeMethod,并针对该函数提供了多个重载,如下

 [static] bool QMetaObject::invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, QGenericReturnArgument ret, 
 QGenericArgument val0 = QGenericArgument(nullptr), 
 QGenericArgument val1 = QGenericArgument(), 
 QGenericArgument val2 = QGenericArgument(), 
 QGenericArgument val3 = QGenericArgument(), 
 QGenericArgument val4 = QGenericArgument(), 
 QGenericArgument val5 = QGenericArgument(), 
 QGenericArgument val6 = QGenericArgument(),
 QGenericArgument val7 = QGenericArgument(), 
 QGenericArgument val8 = QGenericArgument(), 
 QGenericArgument val9 = QGenericArgument())

参数详解

  • 函数返回值,方法调用成功,true;否则false//
  • obj:被调用函数的对象
  • member:被调用的函数
  • type:连接类型,与信号槽的connect的连接类型一致
    • Qt::DirectConnection: 立即调用
    • Qt::QueuedConnection, 应用程序进入抓循环立即发送事件并调用函数
    • Qt::BlockingQueuedConnection, 当线程被阻塞后需要等待线程被释放后执行,否则同QueuedConnection,注意,同一线程中的两个对象调用该方法连接,将会死锁
    • Qt::AutoConnection, 同一线程,同步调用;否则异步调用
  • ret:调用函数member的返回值
  • val0-val9:输入值。

该函数提供了多个版本的重载,如
输入参数忽略连接类型,为Qt::AutoConnection

bool QMetaObject::invokeMethod(QObject *obj, const char *member, 
QGenericReturnArgument ret, 
QGenericArgument val0 = ..., 
QGenericArgument val1 = ..., 
QGenericArgument val2 = ..., 
QGenericArgument val3 = ..., 
QGenericArgument val4 = ..., 
QGenericArgument val5 = ..., 
QGenericArgument val6 = ..., 
QGenericArgument val7 = ..., 
QGenericArgument val8 = ..., 
QGenericArgument val9 = ...)

不关心被调用函数的返回值

[static] bool QMetaObject::invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type,
QGenericArgument val0 = ..., 
QGenericArgument val1 = ..., 
QGenericArgument val2 = ..., 
QGenericArgument val3 = ..., 
QGenericArgument val4 = ..., 
QGenericArgument val5 = ..., 
QGenericArgument val6 = ..., 
QGenericArgument val7 = ..., 
QGenericArgument val8 = ..., 
QGenericArgument val9 = ...)

既采用默认连接方式也不关心返回值

[static] bool QMetaObject::invokeMethod(QObject *obj, const char *member, 
QGenericArgument val0 = ..., 
QGenericArgument val1 = ..., 
QGenericArgument val2 = ..., 
QGenericArgument val3 = ..., 
QGenericArgument val4 = ..., 
QGenericArgument val5 = ..., 
QGenericArgument val6 = ..., 
QGenericArgument val7 = ..., 
QGenericArgument val8 = ..., 
QGenericArgument val9 = ...)
只要掌握了第一种(最复杂的那种)情况,其余的也就掌握了。

示例代码

QMetaObject::invokeMethod(this, [this, name, level]()
   							{
   								updateLevels(name.toUtf8().data(), level, 0, 0);
   							}, Qt::QueuedConnection);//不关心返回值也无需输入参数
    if(QMetaObject::invokeMethod(m_pOne, "slotAdd",
                                 Qt::AutoConnection,
           QGenericReturnArgument("int", poutput)//poutput为指针
           ,Q_ARG(int, 5),
           Q_ARG(int, 6)
           ))
   {
      qDebug()<<"integer"<
    //m_pOne为被连接的对象,
    //add为被连接的函数,实现加和计算
    int re;
    if(QMetaObject::invokeMethod(m_pOne, "add",
                                  Qt::AutoConnection,
            Q_RETURN_ARG(int, re)//re需提前定义
            ,Q_ARG(int, 7),
            Q_ARG(int, 8)
            ))
    {
       qDebug()<

你可能感兴趣的:(qt,开发语言)