Call an async slot without connecting to it using a clear line of code

I ran into a rather bizarre error - QAction::trigger

a blocking dialog popped up, causing my server that called to trigger

be stuck (for example, unable to process socket signals until the dialog was closed).

I figured out a workaround. I connect the signal void triggerWorkaround()

to the slot QAction::trigger

with 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);

      

But these are three lines of confusing code. Is there some weird way to do this? I found QMetaObject::invokeMethod

, but frankly 10 times more confusing than my current solution. Also, I don't want to use the method name as a string!

+1


source to share


1 answer


You can split it 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);
}

      

This will use the signal destroyed()

emitted from the temp QObject

to place the queue event in the event loop. The slot / functor is actually called when the event loop handles that event.

So, instead of the three lines printed out, you can use the above function like this:



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

      


My answer is based on this excellent answer about executing a functor in a given one QThread

. You can contact him for more information.

+2


source







All Articles