5

Is there a safe way to use Qt without calling QApplication::exec()?

I have a number of different objects that are carrying out long-lived processes on multiple resources (at least one of them is communicating with a web application server). I'm making a GUI application that prompts the user for input at the right time for these different processes. I'd like to have my 'flow' logic - the logic that determines what to do next - in one place and not in a GUI object like a dialog class. I was thinking that I could do something like this:

...

wait_dialog dlg;
dlg.setModal( false );
dlg.show(); // Should return...

netobject.start_long_lived_process_that_happens_on_other_thread( &completion_callback );
while ( !completion_callback_called() )
{
    qApp->processEvents();
    netobject.pump_callbacks();
    magically_avoid_busywait_while_still_servicing_qt_somehow();
}

dlg.hide();

...

Is this safe, from Qt's point of view? Is there a 'good' way of implementing magically_avoid_busywait_while_still_servicing_qt_somehow()?

What I'm trying to accomplish here is to write our processing flow in the most explicit way possible. I'd like a single function that does this:

 show_a_non_modal_wait_dialog()

 start_some_processing_1()

 wait_for_processing_1_to_finish()

 dismiss_non_modal_wait_dialog()

 show_modal_input_dialog()

 if ( cancelled ) return

 show_a_non_modal_wait_dialog()

 start_some_processing_2()

 wait_for_processing_2_to_finish()

 dismiss_non_modal_wait_dialog()

 show_modal_input_dialog()

 if ( cancelled ) return

 ...

What I really want to avoid is kicking off and waiting for the processing inside Qt widgets and windows. Also, the processing objects themselves are entirely independent of Qt. I suppose what I'm trying to do is create a controller in a single function with a few helper callbacks and status variables.

Ted Middleton
  • 6,859
  • 10
  • 51
  • 71
  • I guess I'm not sure why you need to halt event processing for this. I believe a QTimer set to 0 ms will run anytime the gui has a chance, and can be used to collect signals from other threads to run code on the gui thread and avoid any thread hell. So you're thread object (QThread) can go about it's business and emit a signal when it needs input, then halt itself. The gui thread catches that signal, prompts the user, gives the thread the result. Then the thread can continue. Or am I misunderstanding? – Thadeux Oct 03 '12 at 23:41
  • Our application has a clear demarcation line between the Qt-bits and the rest of our application. Most of our source files (including the main function above) are not being run through the moc tool and can't emit or receive Qt signals. – Ted Middleton Oct 03 '12 at 23:46
  • While it would be possible to do this function hanging off of the QApplication's idle timing, it means the function would have to be re-entered and would become an ugly state machine. What I was hoping for was a single function that could run from beginning to end - that would make the program flow very explicit. – Ted Middleton Oct 03 '12 at 23:48
  • I'm trying to find an alternative to passing the `netobject` around to all of our GUI windows and dialogs and having THEM initiate processing (which IMHO conceals the overall connection/processing flow). – Ted Middleton Oct 03 '12 at 23:49
  • Signals and slots are pretty much function pointers. You should be able to accomplish the same thing with one of those out of the thread. I'm not entirely sure what Qt will do if you never call QApp::exec, my guess is that it won't care, but you might want to check the source just to be sure. – Thadeux Oct 03 '12 at 23:49

1 Answers1

5

What you want is an event loop other that the application's main event loop. This can be done using the QEventLoop:

wait_dialog dlg;
dlg.setModal( false );
dlg.show(); // Should return...

QEventLoop loop;
connect(&netobject, SIGNAL(done()), &loop, SLOT(quit()));
netobject.start_long_lived_process_that_happens_on_other_thread();

loop.exec(); // BLOCKING (non-busy) until quit() is called via the signal done()

While this is (in my eyes) clean code, this requires your netobject class to be a QObject and implement a signal done() (which is also cleaner than providing callbacks).

Now you can wrap this whole code in a function which will be a blocking call on itself, so it can return some results from your dialog if you want so.

leemes
  • 44,967
  • 21
  • 135
  • 183
  • Ah, since you extended your question about the piece of information that the object is not Qt-related, I want to add that you can also create a callback method just quitting a specific QEventLoop instead of doing this connection. This will be the same, essentially. – leemes Oct 04 '12 at 00:19
  • I'm going to mark this as 'the answer'. I like that it completely avoids processEvents() which seemed to be a bit dodgy and seemed to have some dangerous exceptions that I didn't understand (like DeferredDelete events?). – Ted Middleton Oct 04 '12 at 18:55
  • You have no idea how much this helped me! – Luca Jan 21 '16 at 16:13
  • @leemes does this cause any problems with the main eventloop, or are both running in parallel without intersections? And if not is there a way to prevent these possible problems from occuring ? – user3085931 Feb 29 '16 at 09:24
  • When I try this I get: - QEventLoop: Cannot be used without QApplication – Waslap Jul 28 '23 at 09:36