QProgressDialog does not take input unless the progress value changes
-
I have a classic QProgressDialog and while the processing proceeds the method "wasCanceled()" is regularly called to check if the user pressed the Cancel button. This works, but as long as the progress value is not changed the Clear button is completly unreactive. You can click on it but wasCanceled() will return false. Only when the progress value changes the click on the button is captured. Unfortunately, in this case it is not possible to increasing the update of the progress value.
I tried this when checking for cancelation:
progress->setValue( progress->value() ); canceled = progress->wasCanceled();
but that does not help, still got false as return value.
My fix for the moment is:
int value = progress->value(); progress->setValue( value+1 ); progress->setValue( value ); canceled = progress->wasCanceled();
and this works. But this is ugly of course.
Is there another solution to this? -
When you block the event loop - how should the ui be redrawn? Use the canceld() signal and don't block the event loop...
-
At some point the mouse events need to be processed. For this the event loop needs to run. It is very likely that you are blocking the event loop. There might be some weird behavior when calling setValue with a different progress that uses some direct connection to update the progress bar and also somehow processes the mouse event.
As a quick test you can call QApplication::processEvents() right before your call to wasCanceled() to see if this solves your problem. If it does you are definitely blocking the event loop. However, don't use this trick as your final solution. Your current loop will take about 100 times longer if you do this. It is not worth to slow down your actual processing by 100x just to have a nice UI.
Instead, then your solution should be to use a separate worker thread. You are not allowed to call any UI functions from the worker thread: no call to wasCanceled and no call to setValue. Instead you need to use signals and slots to connect these function calls.
-
@JanLaloux You’re right! Manually incrementing and resetting the progress value is not ideal. A cleaner approach could be calling QCoreApplication::processEvents() inside your loop to allow UI events (like button clicks) to be processed without artificially changing the progress value. You might also try setAutoReset(false) or setMinimumDuration(0) to see if it improves responsiveness.
-
@andrewmorgan
It would not be ideal to callprocessEvents()
. It would be better to allow the main event loop to run and raise and act on thecanceled()
signal, as previously written. -
Thanks all for the valuable input!
@SimonSchroeder: the test with QApplication::processEvents() is positive, the problem goes away.
BUT: the implementation is as documented for the QProgressDialog Class for the modal operation:
"Compared to a modeless QProgressDialog, a modal QProgressDialog is simpler to use for the programmer. Do the operation in a loop, call setValue() at intervals, and check for cancellation with wasCanceled(). "
So with the functions, not the signals.
And since it is the intention that the user cannot do anything than either wait for the operation to finish, or to cancel it, this seems to me correct for the modal operation? -
@JonB said in QProgressDialog does not take input unless the progress value changes:
It would not be ideal to call processEvents()
The only valid use case for
processEvent()
to update the progress ofQProgressDialog
/QProgressBar
is when using it in combination with tasks that run inmain.cpp
before the event loop is even started or like everythingQSplashScreen
related...