异步调用插槽,而无需使用清晰的代码行连接到插槽 [英] Invoke slot asynchronously without connecting to it using clear line of code

查看:111
本文介绍了异步调用插槽,而无需使用清晰的代码行连接到插槽的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了一个怪异的错误-QAction::trigger导致出现阻塞对话框,这导致我的调用trigger的服务器卡住(例如,直到对话框关闭后才能处理套接字信号).

I have encountered quite freaky bug - QAction::trigger caused blocking dialog to appear, which caused my server which called trigger to go stuck (eg. not able to process socket signals until dialog was closed).

我想出了一种解决方法.我使用Qt::QueuedConnection将信号void triggerWorkaround()连接到插槽QAction::trigger并发出信号:

I figured out a workaround. I connect signal void triggerWorkaround() to slot QAction::trigger using Qt::QueuedConnection and I emit it:

QObject::connect(this, &HackClass::triggerWorkaround, targetAction_.data(), &QAction::trigger, Qt::QueuedConnection);
emit triggerWorkaround();
QObject::disconnect(this, nullptr, targetAction_.data(), nullptr);

但这是三行令人困惑的代码.有没有混淆的方法可以做到这一点?我发现 QMetaObject::invokeMethod ,但是坦率地说,这比我当前的解决方案混乱了10倍.另外,我不想将方法名称用作字符串!

But that's three lines of confusing code. Is there a non-confusing method to do this? I have found QMetaObject::invokeMethod, but frankly, that's 10 times more confusing than my current solution. Also, I don't want to ever use method name as string!

推荐答案

您可以将其分成函数QueuedInvoke,如下所示:

You can separate that into a function QueuedInvoke like this:

//overload for methods/slots
//the slot gets invoked in the thread where the QObject lives
template <typename Object, typename T>
void QueuedInvoke(Object* object, T (Object::* f)()){
    QObject signalSource;
    QObject::connect(&signalSource, &QObject::destroyed,
                     object, f, Qt::QueuedConnection);
}
//overload for functors
//the functor gets invoked in the thread where the contextObject lives
//or in the current thread if no contextObject is provided
template <typename Func>
void QueuedInvoke(Func&& f, QObject* contextObject = QAbstractEventDispatcher::instance()){
    QObject signalSource;
    QObject::connect(&signalSource, &QObject::destroyed, 
                     contextObject, std::forward<Func>(f), Qt::QueuedConnection);
}

这将利用从临时QObject发出的destroyed()信号将排队的事件发布到事件循环中.当事件循环处理该事件时,实际上会调用slot/functor.

This will leverage the destroyed() signal emitted from the temporary QObject to post a queued event into the event loop. The slot/functor is actually invoked when the event loop processes that event.

因此,您可以像上面那样使用上面的函数,而不是您发布的3行:

So, Instead of the 3 lines you posted, You can use the above function like this:

QueuedInvoke(targetAction_.data(), &QAction::trigger);


我的答案基于关于在给定的QThread中执行函子的很好的答案.您可以参考它以获取更多详细信息.


My answer is based on this great answer about executing a functor in a given QThread. You can refer to it for more details.

这篇关于异步调用插槽,而无需使用清晰的代码行连接到插槽的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆