PDA

View Full Version : occasional frozen QProgressDialog with QFutureWatcher



ibex
26th October 2010, 16:32
Hi,

I'm having occasional trouble with a QProgressDialog connected to a QFutureWatcher (Qt4.6.2, x11). For roughly one in five occasions where the QFuture calculation is almost instantaneous (but never when it takes several seconds or more), the dialog appears empty with no cancel button or progress bar and can't then be closed.

Using something like the following (the watcher and dialog can be reused for different calculations):


class MyClass {
QProgressDialog mProgress;
QFutureWatcher mWatcher;
};

MyClass::MyClass() {
connect(&mWatcher, SIGNAL(finished()), &mProgress, SLOT(reset()));
connect(&mWatcher, SIGNAL(progressValueChanged(int)), &mProgress, SLOT(setValue(int)));
connect(&mWatcher, SIGNAL(progressRangeChanged(int,int)), &mProgress, SLOT(setRange(int,int)));
connect(&mProgress, SIGNAL(canceled()), &mWatcher, SLOT(cancel()));
connect(&mWatcher, SIGNAL(canceled()), &mProgress, SLOT(cancel()));
}

void MyClass::calculate() {
mWatcher.setFuture(QtConcurrent::map(begin(), end(), Calculator()));
}

My initial thought was that the map completes before all connections to the watcher can be made. However I have tried connecting debugging printing slots to the QFutureWatcher and all appropriate signals are being sent and received in the appropriate order. mWatcher.isRunning() always returns true immediately after the setFuture() call.

One other possibility would be as the manual says:
Note that if you set a new maximum (using setMaximum() or setRange()) that equals your current value(), the dialog will not close regardless
However debug printing shows this is also not the case.

Any ideas would be gratefully received.

wysota
26th October 2010, 19:10
How large is your map? Is it possible that jobs are completed so fast that the GUI thread doesn't have time to rerender the dialog before a subsequent task ends? In other words, maybe the dialog gets starved by the background tasks?

ibex
26th October 2010, 21:30
Generally between 1 & 1000 items in the map, however sometimes it already contains most of the results and doesn't need much further processing (ie. the map takes from <<1s to ~60s). For whatever reason, very fast completion can cause this problem and it may well be thread starvation as you say.

However wouldn't the dialog be re-rendered in the GUI thread once the map has finished? In fact in this case it just contains an empty gray rectangle, but does repaint (only as the rectangle) when resized or obscured by other windows. I don't understand how it can get stuck in such a state and what I can do about it.

thanks.

wysota
26th October 2010, 21:40
However wouldn't the dialog be re-rendered in the GUI thread once the map has finished? In fact in this case it just contains an empty gray rectangle, but does repaint (only as the rectangle) when resized or obscured by other windows. I don't understand how it can get stuck in such a state and what I can do about it.
So you mean it stays that way regardless of what your application is doing? Can you resize other windows and observe them being repainted correctly?

ibex
26th October 2010, 21:48
Yes it stays that way until another map operation is started. Usually, and always if it takes several seconds, the subsequent map causes the QProgressDialog to recover normal behaviour and hide on completion. When the QProgressDialog is not working, the rest of the application still behaves correctly.

wysota
26th October 2010, 22:34
Could you try to prepare a minimal compilable example reproducing the problem?

ibex
27th October 2010, 11:17
Yes, I will see if I can recreate it.

ibex
27th October 2010, 21:34
5407 is a small example based on a Qt one. Unfortunately I have only managed to recreate the problem twice with it. Pressing the run button will start the map operation, and after many presses the progress dialog may fail (it is normally not shown with the coded constants due to the short run time).

I have tried changing the size of the map task, and adding a slow paintEvent() method to the window but can't yet make the problem more repeatable. I can't think of any other relevant differences to my application at the moment.