Qt invokeMethod 异步调用

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Qt invokeMethod 异步调用相关的知识,希望对你有一定的参考价值。

参考技术A

程序中,我们经常会调用函数,如果调用的函数耗时较长,同步调用会造成主程序的堵塞。Qt中提供了一个便捷的函数 QMetaObject::invokeMethod ,方便我们异步调用,从而解决这一问题。本文只要讲述 QMetaObject::invokeMethod 的使用方法。

此函数用于调用对象的成员(信号或插槽)。如果可以调用成员,则返回true。如果没有此类成员或参数不匹配,则返回false。
QMetaObject::invokeMethod 除上文这个函数以外还有5个重载函数,这里不再赘述。
参数说明:
obj :被调用对象的指针
member :成员方法的名称
type :连接方式,默认值为 Qt::AutoConnection

ret :接收被调用函数的返回值
val0 ~ val9 :传入被调用函数的参数,最多十个参数
注:必须要使用 Q_RETURN_ARG() 宏来封装函数返回值、 Q_ARG() 宏来封装函数参数。

若一个对象obj有一个槽函数func(QString,int),返回值为bool,那么调用方式如下:

注: 使用 Qt::QueuedConnection 异步调用,将无法获取返回值,因为此连接方式只是负责把事件交给事件队列,然后立刻返回,所以,函数返回值就无法确定了。
但,我们可以使用上文提及的 Qt::BlockingQueuedConnection 连接方式,这个连接方式会阻塞发射信号的线程一直等到队列连接槽返回后,才会恢复阻塞,这样就可以保证我们能得到函数的返回值。使用如下:

需要注意的是,qt官方文档中的提醒: 使用此连接类型在同一线程中的对象之间进行通信将导致死锁

最后,因为连接方式 type 默认值为 Qt::AutoConnection ,所以当被调用的obj与调用者不在同一线程中,可以直接调用:

使用 QMetaObject::invokeMethod 来调用函数时,当函数的参数有自定义类型时,程序将会报错,因为调用的类型必须是信号、槽,以及Qt元对象系统能识别的类型。可以使用Qt命名类型所提供的 qRegisterMetaType() 来注册自定义类型。
示例如下:

QMetaObject::invokeMethod 不调用槽

【中文标题】QMetaObject::invokeMethod 不调用槽【英文标题】:QMetaObject::invokeMethod does not call slot 【发布时间】:2021-07-11 23:15:09 【问题描述】:

我在工作区管理器类中有一个名为 UpdateScreenshots 的公共信号,它可以截取一些小部件的屏幕截图。然后它在我定义的结构中返回这些屏幕截图。这个调用是从一个线程进行的,因为截屏显然只能在主线程上完成。但是,此 invokemethod 调用不起作用,并且未调用 updatescreenshots 插槽。我可能做错了什么? 有没有更好的方法来做到这一点?

invokeMethod 调用

VmsWorkspaceManager::InfoStruct info;

QMetaObject::invokeMethod(m_Manager, "UpdateScreenshots", Qt::BlockingQueuedConnection,
Q_RETURN_ARG(Vms::GuiWidgets::VmsWorkspaceManager::InfoStruct, info));

槽的定义;

public slots:

/**
* \brief Updates the current screenshots to be sent to a remote client
*/
InfoStruct UpdateScreenshots() const;

【问题讨论】:

【参考方案1】:

首先,确保您在 InfoStruct 标头的底部有此声明:

Q_DECLARE_METATYPE(Vms::GuiWidgets::VmsWorkspaceManager::InfoStruct)

然后,在您的 main 函数之上,进行以下调用:

int main(int argc, char *argv[])

    qRegisterMetaType<Vms::GuiWidgets::VmsWorkspaceManager::InfoStruct>("Vms::GuiWidgets::VmsWorkspaceManager::InfoStruct");

由于您使用的是命名空间,因此您必须与它们非常保持一致,因此请确保槽签名是这样的:

Vms::GuiWidgets::VmsWorkspaceManager::InfoStruct UpdateScreenshots() const;

【讨论】:

以上是关于Qt invokeMethod 异步调用的主要内容,如果未能解决你的问题,请参考以下文章

Qt Meta Type System

仅从 C++ API 进行异步调用,Qt 网络通道迁移看起来是不可能的

Qt带返回值的信号发射方式(使用QMetaObject::invokeMethod)

aboutToQuit 期间的 Qt 异步操作

异步显示 Qt 对话框

QT 异步函数转为同步函数的方法