Update QProgressBar from QThread
-
Hi!
I am using a QThread object to perform a heavy computation and I also have a QProgressBar in my main gui thread that I am updating accordingly. Everything works fine except that I am only able to update my progress bar after a certain number of iterations.
In one hand, in case I emit a signal in each operation my gui freezes. On the other hand, if I use the flag Qt::BlockingQueuedConnection in the connection from the signal in the new thread to the slot of the progress bar, the gui does not freeze but the process takes a lot longer to compute.
I know that if I emit a signal in each iteration step, the main thread gets busy trying to update the bar with a huge amount of queued signals. However, I am wondering if there is a suitable method to update the progress bar smoothly without compromising both the working and gui threads.
-
Hello @Astrinus ,
Does make sense to have (I guess) more than 10 progress update per second?
No, it really does not. I was just asking because it could exist a better way to implement this.
Or you have a coarser "unit of progress" at hand?
What I am currently doing is to emit the signal only if the iteration step is equal to a multiple of a certain part of the total iterations required to perform the computation. Is this what you mean by "throttle signal emission"?
-
@Tiago-M-Pinto said in Update QProgressBar from QThread:
wondering if there is a suitable method to update the progress bar smoothly without compromising both the working and gui threads
Simply emit the signal after some amount of work was done, like 1% for example
-
I recently experimented with having the work done in a separate thread. However, the progress dialog still needs to run in the GUI thread. This evolved into a small helper library (header-only): https://github.com/SimonSchroeder/QtThreadHelper . See the use case 2 for how to use it for a progress dialog. Instead of calling
workerThread
you can use your current implementation of a separate thread.What I figured out during implementation and experimentation of this library is that when queuing update requests to the progress dialog into the main queue these request might overtake each other. The library takes care of serializing these requests. Still, this requires some throtteling because otherwise the stack might quickly become too deep.
One other thing I learned is that a modal progress dialog automatically calls
processEvents
. So, I turned it off just for this one update because the events where handled differently. You should note that if you have a cancel button in your progress dialog you have to make sure that the GUI stays responsive. It is very frustrating if clicking 'cancel' is not reacting...For throtteling yesterday I came up with a different idea. I used to throttle based on number of iterations as well. This, however, might be too few or too many updates if the amount of work per iteration might vary with different inputs. You can use
QTime
andelapsed()
to make updates to the progress more regular.QTime lastUpdateTime; lastUpdateTime.start(); ... for(/* your work loop */) { /* do work */ if(lastUpdateTime.elapsed() > 500 /* || first iteration || last iteration */) { /* update progress */ lastUpdateTime.restart(); } }