Details
-
Bug
-
Resolution: Unresolved
-
P4: Low
-
None
-
4.7.0, 4.7.1, 4.7.2
-
None
-
Windows (XP SP3), VC2008, QT 4.7.2
Description
In this commit:
http://qt.gitorious.org/qt/qt/commit/0f771c62f5253a969f5a8a81bfd9254b9bd58b8f
QTime was Replaced by QElapsedTimer. One effect of this that was missed (I think!) for QProgressDialog is that a timer needs to be started, while a QTime doesn't (or more correct: QTime seems to have fallback). There are ways to end up using the timer without starting it in the current QProgressDialog, that appear to me to be normal usage of QProgressDialog. When this happens, it causes the dialog to not show up automatically, in some cases (depending on the value in uninitialized memory).
Note: I'm guessing this is also the cause for QTBUG-9600 .
Looking at the QProgressDialog code
===================================
The timer is only started in QProgressDialog::setValue :
if (progress == 0) {
d->starttime.start();
however, if you never pass a 0 progress (and this usually happens if you try to do progress for networking, e.g. QHttp etc), or even if you do setValue(0) without setting the maximum higher than 0 first (e.g.in the cases where QHttp does not return a 'total' so there is no maximum to set), the QElapsedTimer d->starttime is never started. On the first setValue of something bigger than 0, this happens:
int elapsed = d->starttime.elapsed(); if (elapsed >= d->showTime) { need_show = true;
and the windows implementation of elapsed() returns getTickCount() - t1, where t1 is not initialized memory if the timer was not start()-ed (0xcdcdcdcd on windows with DEBUG_NEW).
Workaround: artificially bypass the problems in QProgressDialog code by calling setMaximum(1), then setValue(0), then setMaximum(0) (the last one is needed if you don't know the real maximum, e.g. in the download case where the http server does not return the size).
Code Fix:
- fix QElapsedTimer to work more like QTime? Eg QTime's ds():
inline int ds() const { return mds == -1 ? 0 : mds; }
This seems to check if it has been started/initliased/...?
- move d->starttime.start(); before the 'if (progress == 0)', or even to creation? Or check if the timer has already been started (QElapsedTimer::isValid() I think)?
- some other change to QProgressDialog code to avoid this situation.
Test Code
=========
Take the code from the QProgressDialog help, and replace the initial value of steps with 1:
// Operation constructor Operation::Operation(QObject *parent) : QObject(parent) , steps(1) //NOTE 1, and no dialog is ever shown, 0 and it's ok { pd = new QProgressDialog("Operation in progress.", "Cancel",0,100); connect(pd, SIGNAL(canceled()), this, SLOT(cancel())); t = new QTimer(this); connect(t, SIGNAL(timeout()), this, SLOT(perform())); t->start(100); } void Operation::perform() { pd->setValue(steps); //... perform one percent of the operation steps++; if (steps > pd->maximum()) t->stop(); } void Operation::cancel() { t->stop(); //... cleanup }