1

I'm working on Qt 5.5 with Qt Creator. I have a big class called settingsWindow that, as the name should suggest, takes care of various settings. These settings are then used to start some QDialogs which show a very complex animation on a scene inside a qGraphicsView, that is updated constantly via QCoreApplication::processEvents(), whoch in turn mantains the GUI responsive. The animation is started via the method start() of the QDialog. I'd like to run these QDialogs simultaneously, for example via a button start that starts all of them in the same moment. I tried using a wrapper, that is, a simple class inheriting from QObject, assigning it to a different thread each time, but still if I start a QDialog all goes fine, when I start the second one, the first one "blocks" (animation stops and only in the second Qdialog the animation is visible). The only solution I have is to start a separate QProcess for each of them (in this way I am sure they run separately and are on different threads), but I would need to rewrite the logic (separate programs for each QDialog).

Any simpler solution? Thank you in advance.

Michael
  • 876
  • 9
  • 29

2 Answers2

1

It can't be done from within a single process. Anything touching a QWidget can only run in the main thread. That your code happens to run at all is a coincidence, you're depending on undefined behavior and Qt was never meant to be used that way. There are no tests for this, and so on: you're on your own and you'd have to dig deeply into Qt code to figure out what to change to allow any of this.

If you're doing animations that are too complex to render in the GUI thread, and you insist on using the legacy widgets, you'll have to render them using QPainter into a QImage, as asynchronous work via QtConcurrent::run. The async worker will then signal the images to the dialog, the latter will then blit them to the screen.

See this answer for links to two relevant examples.

Otherwise, use QML. For most things, from the CPU perspective the QML animations are almost a no-op. GPU does all the rendering, and it performs admirably.

The multiprocessing approach is of course also doable. Feel free to start the same executable with arguments specifying the random name for the pipe to use for interprocess communication, and to modify behavior (1st vs. 2nd dialog etc.). See this answer for how to launch yourself easily.

Community
  • 1
  • 1
Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
  • What do you exactly mean with "That your code happens to run at all is a coincidence"? Did you mean trying to move a QDialog in a thread? I think I will go on with my idea of a separate process for each QDialog. I don't need inter-process communication as regards communication between QDialogs (they actually do not return anything, and they work on fully different variables from the settingsWindow). The "animation" is actually a graph-construction, starting from a source node and trying to reach a target node, adding new points and lines to the scene. Is QPainter a nice way to render this? – Michael Nov 06 '15 at 22:12
  • *Did you mean trying to move a QDialog in a thread?* Yes. Don't do that. It's not supposed to work, it's not supported, if you have any problems you're literally on your own (unless you hire someone, of course). *The "animation" is actually a graph-construction, starting from a source node and trying to reach a target node* Separate the data and the algorithms that run on it from the visualization. That's your problem. The rendering isn't too slow, most likely. Your computations are slowing the rendering, though. – Kuba hasn't forgotten Monica Nov 09 '15 at 14:31
0

It's hard to help with no piece of code posted.

You may try to create a thread for each dialog and then move one dialog to each thread (using QObject::moveToThread).

Each thread will have to give the other ones a chance to execute instructions some time to time (calling QThread::yieldCurrentThread or QThread::sleep). Else, if one thread is in a huge loop doing something it will never gve the other ones a chance to do something.

jpo38
  • 20,821
  • 10
  • 70
  • 151
  • Yes, in fact it is that huge loop that causes a thread to block the other. I thought that, since I have a multi-core processor, each generated thread would automatically be assigned to another core, but it does not seem this case. The strange thing is that anyway the GUI is responsive in each QDialog (I also have a simple chronometer in each QDialog that shows the elapsed time since the start, and it continues to run smoothly). How do you suggest to implement the stop of a thread to let the other going on? A `QTimer` that each 100 ms swap from a thread to another? Does not it cause overhead? – Michael Nov 06 '15 at 20:31
  • Try to call `yieldCurrentThread` from the threads, this will pass the control to another one. – jpo38 Nov 06 '15 at 20:39
  • How? If I create the two QDialogs, then do `QThread* t1 = new QThread; QThread* t2 = new QThread; dialog1->moveToThread(t1); dialog2->moveToThread(t2); dialog1->show(); dialog2->show(); dialog1->start(); dialog2->start();` Should I use a `QTimer` and every `n` ms sleep/yield a thread and continue with the other? – Michael Nov 06 '15 at 20:51
  • Yes, try something like that. Or insert a yield instruction in your processing loop. – jpo38 Nov 07 '15 at 08:45