摘要
如果用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"<<poutput;
result.append(output) ;
}
//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()<<re;
}