PDA

View Full Version : How to query the user for input from outside the Qt Message Loop



so Qt
15th May 2015, 00:54
Hi,

Qt suggests to run computationally expensive tasks in dedicated worker threads instead of SLOTs itself. How do you go about the problem of doing things like showing message boxes to the user and query for their input? The only solution I can think of is to emit a SIGNAL from within the worker thread to a class which shows the MessageBox and emits back a SIGNAL about the user's choice. This however seems overly complicated and messes up my code and control flow with additional sigslot connections. Is there a nicer solution to this or at least some way to abstract this away in a wrapper class somehow?

I wonder how others go about this.

wysota
15th May 2015, 06:21
You can use either signals or events or you can resign from using threads in this code in favor of some other approach (e.g. dividing the task into subtasks and doing them separately to avoid blocking the event loop for too long).

so Qt
15th May 2015, 12:10
Yes, dividing into subtasks or doing sth similar is probably the easiest way to go in most cases but it's not always possible, especially when talking about legacy code. And lets say we have sth like this then:


void slot_myAlgorithm()
{
// spawns thread and joins at its end
if(!runSubtask1())
showError();

if(!runSubtask2())
showError();

if(!runSubtask3())
showError();
}

What if another developer wants to reuse this entire algorithm pipeline from inside another thread? Then he again runs into this threading trouble and either has to restructure or copy existing code both of which should be avoided imo.

And as another example: What if I'm using an std::thread which requires a static run function where I can't emit any signals from because it's not a QObject?

anda_skoa
16th May 2015, 10:08
You can always use QMetaObject::invokeMethod() to call a slot in a QObject in another thread (the function can be given the necessary Qt::QueuedConnection flag).

Alternatively to the signalling back you could just block the worker thread and wait for the UI thread to call a method that passes the response.
E.g. emit the signal and calling acquire on a binary semaphore.
When the UI has the user's answer, it calls a setter method which calls release() on the semaphore after setting the value.

The worker thread can then continue reading the value.

Cheers,
_