Solved Update GUI from QThread
-
I want update (animate) a widget independent from the main thread.
Here is my Thread:void MyThread::run() { while(true) { emit timerElapsed(); msleep(100); k17++; qDebug()<<"run "<<k17; } //start(); emit timerElapsed(); }
Here is my connection
connect(&mythread, SIGNAL(timerElapsed()), ui->advCircularProgress, SLOT(nextStep())); mythread.start();
This should work - but it does not.
When I start a time consuming action in the main thread (Database-Table-refresh)
the animation stops. It seems that it is not primary a repaint problem, but the
emit timerElapsed() does not receive the widget nextStep(); when it is emitted
It receives all pending signals in a queue later, when the main thread is ready.What do I wrong!
-
@Andy314
The painting and GUI happens all in the main thread, you can't change that. When you have multiple threads the receiver slot's object determines in which thread the slot will be invoked (see QObject's thread affinity documentation). So what you're doing is to schedule the updates in the main thread. This is why when the event loop of the main thread is busy you get the repaints done later. -
@kshegunov
You say that it is not possible to make independent GUI-animation from the main thread !?
I must write everywhere QCoreApplication::processEvents(); ?
For my own code this is uncomfortable but possible - for other code in libs this is not possible.
Taking the time consuming code in a other thread works for pure code but usually I make here other GUI stuff too.Is there really no solution for forcing a widget update from a other thread ?
-
must write everywhere QCoreApplication::processEvents(); ?
This processes the events, nothing more, I'd suggest redesigning your code so you don't need to call that function at all (for example running your thread with an event loop and a timer, not subclassing
QThread
).Taking the time consuming code in a other thread works for pure code but usually I make here other GUI stuff too.
You can prepare in a worker thread whatever is that needs to be done in the GUI and schedule the painting at the appropriate times (by signal-slots), the painting itself, however, will (and should) be happening in the main thread.
Is there really no solution for forcing a widget update from a other thread ?
You can only request a widget to be repainted from another thread, when the event that's posted gets processed the widget itself will be updated. If you want to directly repaint a widget from a thread different from the main, well, that's not possible. I don't know any toolkit to support threaded GUI in any case (OpenGL painting excluded).
-
@Andy314 said:
When I start a time consuming action in the main thread (Database-Table-refresh)
the animation stops. It seems that it is not primary a repaint problem, but the
emit timerElapsed() does not receive the widget nextStep(); when it is emitted
It receives all pending signals in a queue later, when the main thread is ready.The main thread cannot refresh the database and update the GUI at the same time.
To make your GUI respond quickly, you have 3 options:
- Use a different thread to access your database, OR
- Optimize your database-access code so that it is not time-consuming, OR
- Make your database-access code call QCoreApplication::processEvents() to process signals. (Note: Option #3 is easiest, but it is not a robust design)