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 异步调用的主要内容,如果未能解决你的问题,请参考以下文章
仅从 C++ API 进行异步调用,Qt 网络通道迁移看起来是不可能的