[Solved] Slow program and QProgressDialog problems
-
I have a class function that gets a couple of queries to perform some data manipulation. One of the queries is used to iterate through the results and make the needed changes. The process takes approximately 7 seconds. I then put in a QProgressDialog to let the user know that something was happening. The QProcessDialog didn't show up for several seconds, and then when it did, it showed up and then completed in a fraction of a second. I moved the QProcessDialog up in the code as far as possible and it still took almost 3 seconds before it showed up. The database is not that big (approximately 1000 rows) The rows iterated through are only around 200 and it doesn't appear that the iteration is the problem as the progress dialog once shown updates very quickly.
Here is the code:
@void DlgEditPas::on_btnDelete_released()
{
if (ui->comboBox->currentIndex()== -1)
{
QMessageBox::warning(this, "Nothing Selected", "You do not have a PAS "
"Number selected",
QMessageBox::Ok);
return;
}
int test=QMessageBox::warning(this,"Delete PAS Number", "Are you sure you want to delete this PAS number? ",
QMessageBox::Yes | QMessageBox::No );
if (test==QMessageBox::No)
return;// new location.... it takes almost 3 seconds to show up
QSqlQuery countQuery;
countQuery.exec("SELECT count(*) FROM position WHERE postType = 2");
countQuery.last();
int rowCount = countQuery.value(0).toInt();QProgressDialog progress (this); progress.setLabelText("Deleting relief coverage \n Searching Relief Positions"); progress.setRange(0,rowCount); progress.setValue(0); progress.setModal(true); progress.setCancelButton(0);
//reset form data in case changes were made
m_formIsDirty=false;
on_comboBox_currentIndexChanged(ui->comboBox->currentIndex());//prepare to delete
QString idNum=ui->comboBox->itemData(ui->comboBox->currentIndex()).toString();
QString postNum = ui->txtPostNum->text();
QSqlQuery deletePas;
deletePas.setForwardOnly(true);
deletePas.prepare("DELETE FROM pas WHERE id = " + idNum);
deletePas.exec();QSqlQuery deletePosition; deletePosition.setForwardOnly(true); deletePosition.prepare("DELETE FROM position WHERE postNum = " + postNum); deletePosition.exec();
//Delete relief info from relief posts
QSqlQuery reliefQuery; reliefQuery.setForwardOnly(true); QSqlQuery updateQuery; updateQuery.setForwardOnly(true); QString updateString; reliefQuery.prepare ("SELECT id, mon, tue, wed, thu, fri, sat, sun FROM position " "WHERE postType = 2"); // less than 200 rows reliefQuery.exec();
//old QProgressDialog location here
int tempCount=0;
while(reliefQuery.next()) { tempCount ++; progress.setValue(tempCount); for (int i=1; i<8; i++) { if (reliefQuery.value(i).toString()==postNum) { switch (i) { case 1: //day is Monday updateString ="UPDATE position SET mon = '#####' WHERE id = " + reliefQuery.value(0).toString(); break; case 2: //day is Tuesday updateString ="UPDATE position SET tue = '#####' WHERE id= " + reliefQuery.value(0).toString(); break; case 3: //day is Wednesday updateString ="UPDATE position SET wed = '#####' WHERE id = " + reliefQuery.value(0).toString(); break; case 4: //day is Thursday updateString ="UPDATE position SET thu = '#####' WHERE id = " + reliefQuery.value(0).toString(); break; case 5: //day is Friday updateString ="UPDATE position SET fri = '#####' WHERE id = " + reliefQuery.value(0).toString(); break; case 6: //day is Saturday updateString ="UPDATE position SET sat = '#####' WHERE id = " + reliefQuery.value(0).toString(); break; case 7: //day is Sunday updateString ="UPDATE position SET sun = '#####' WHERE id = " + reliefQuery.value(0).toString(); break; } updateQuery.prepare(updateString); updateQuery.exec(); //qDebug() <<"update for delete relief query"<<updateQuery.lastError(); } } } updateComboBox(); on_comboBox_currentIndexChanged(ui->comboBox->currentIndex());
}@
Any ideas? -
Try to add
@
progress.setMinimumDuration(0);
@bq. From the docs:
If the expected duration of the task is less than the minimumDuration, the dialog will not appear at all. This prevents the dialog popping up for tasks that are quickly over. For tasks that are expected to exceed the minimumDuration, the dialog will pop up after the minimumDuration time or as soon as any progress is set.
If set to 0, the dialog is always shown as soon as any progress is set. The default is 4000 milliseconds.You might want to call "QCoreApplication::processEvents() ":http://doc.qt.nokia.com/4.7/qcoreapplication.html#processEvents from time to time too in order to process pending events in the main event loop.
-
Thanks,
It still takes about 2-3 seconds for the dialog to show. I am not sure where I should put the processEvents function. I am not sure if I need it. Isn't this function to capture any events that might occur while the process is going on? There should not be any events going on when this function is running. And if there is I think I want them ignored.
Thanks for your help. Any idea why it takes so long for the progressDialog to show? -
Does it take 2-3 seconds even after adding progress.setMinimumDuration(0)?
Can you add a QTime and some QDebugs to see how long it takes between the setValue() calls and to get to the first setValue() call?
-
-
roopesh...yes that was after setMinimumDuration(0). I changed the count query and added some QTime debugs to see what is going on. I ran the program a few times and here is what I have:
@void DlgEditPas::on_btnDelete_released()
{
if (ui->comboBox->currentIndex()== -1)
{
QMessageBox::warning(this, "Nothing Selected", "You do not have a PAS "
"Number selected",
QMessageBox::Ok);
return;
}
int test=QMessageBox::warning(this,"Delete PAS Number", "Are you sure you want to delete this PAS number? \n"
"This will also delete the Post associated with this PAS Number \n"
" and the relief (if any) in the Relief posts",
QMessageBox::Yes | QMessageBox::No );
if (test==QMessageBox::No)
return;
QTime elapsed;
elapsed.start();
QSqlQuery countQuery;
countQuery.exec("SELECT count(postNum) FROM position WHERE postType = 2");
qDebug()<<"after count query"<<elapsed.restart(); // 1-2 ms
countQuery.last();
qDebug()<<"after last query"<<elapsed.restart(); // 0 ms
int rowCount = countQuery.value(0).toInt();QProgressDialog progress (this); progress.setLabelText("Deleting relief coverage \n Searching Relief Positions"); progress.setRange(0,rowCount); progress.setValue(0); progress.setModal(true); progress.setCancelButton(0); progress.setMinimumDuration(0);
qDebug()<<"after initializing QProgressDialog"<<elapsed.restart(); // 4ms
//reset form data in case changes were made
m_formIsDirty=false;
on_comboBox_currentIndexChanged(ui->comboBox->currentIndex());//prepare to delete
QString idNum=ui->comboBox->itemData(ui->comboBox->currentIndex()).toString();
QString postNum = ui->txtPostNum->text();
QSqlQuery deletePas;
deletePas.setForwardOnly(true);
deletePas.prepare("DELETE FROM pas WHERE id = " + idNum);
deletePas.exec();
qDebug()<<"after delete pas query"<<elapsed.restart(); // 354-1393ms
QSqlQuery deletePosition;
deletePosition.setForwardOnly(true);
deletePosition.prepare("DELETE FROM position WHERE postNum = " + postNum);
deletePosition.exec();
qDebug()<<"after delete position query"<<elapsed.restart(); // 1475-1501 ms//Delete relief info from relief posts
QSqlQuery reliefQuery; reliefQuery.setForwardOnly(true); QSqlQuery updateQuery; updateQuery.setForwardOnly(true); QString updateString; reliefQuery.prepare ("SELECT id, mon, tue, wed, thu, fri, sat, sun FROM position " "WHERE postType = 2"); reliefQuery.exec();
qDebug()<<"after select relief query"<<elapsed.restart(); // 2-3 ms
int tempCount=0;
while(reliefQuery.next()) { qDebug()<<"after each next step"<<elapsed.restart(); //this is usually 1-3 ms with a few that //that are 10-30ms but once each time //there is one that is around 1500ms //(not the same location) tempCount ++; progress.setValue(tempCount); for (int i=1; i<8; i++) { if (reliefQuery.value(i).toString()==postNum) { switch (i) { case 1: //day is Monday updateString ="UPDATE position SET mon = '#####' WHERE id = " + reliefQuery.value(0).toString(); break; case 2: //day is Tuesday updateString ="UPDATE position SET tue = '#####' WHERE id= " + reliefQuery.value(0).toString(); break; case 3: //day is Wednesday updateString ="UPDATE position SET wed = '#####' WHERE id = " + reliefQuery.value(0).toString(); break; case 4: //day is Thursday updateString ="UPDATE position SET thu = '#####' WHERE id = " + reliefQuery.value(0).toString(); break; case 5: //day is Friday updateString ="UPDATE position SET fri = '#####' WHERE id = " + reliefQuery.value(0).toString(); break; case 6: //day is Saturday updateString ="UPDATE position SET sat = '#####' WHERE id = " + reliefQuery.value(0).toString(); break; case 7: //day is Sunday updateString ="UPDATE position SET sun = '#####' WHERE id = " + reliefQuery.value(0).toString(); break; } updateQuery.prepare(updateString); updateQuery.exec(); } } }
}@
I then added a setValue(1) right after the initialization of the QProgressDialog. And it immediately showed a blank dialog with no label or progressBar for a couple seconds.
From the numbers, it looks like either the QProgressDialog takes 2-3 seconds to show (bad design) or it doesn't show until it reaches the first iterated value and then after a couple iterations, it determines to show or not and if it shows then displays the label and progress bar.
Any Ideas? Or should I create a dialog with a progressBar and set up the signals and slots? -
Volker, thanks, that didn't change anything. However, after looking at the code, a simple solution came to mind. I moved the code where it iterates to right below the QProgressDialog initialization added 2 to the rowcount and then in each delete query I incremented the tempCount and set the value of progress. Now it works as expected....
Thanks for your help as always!!!