0

Consider this SLOT, in my main thread, trigged by a button, which takes a list of QTreeWidgetItem from a QTreeWidget. It uses a QtConcurrent::map() call to execute a long task. The watcher connects to a QProgressDialog to show progress.

void Main::on_actionButton_triggered() {
    qRegisterMetaType<QVector<int> >("QVector<int>");

    //Setting up a progress dialog
    QProgressDialog progressDialog;

    //Holds the list
    QList<QTreeWidgetItem*> list;

    //Setup watcher
    QFutureWatcher<void> watcher;

    //Setting up connections
    //Progress dialog
    connect(&watcher, SIGNAL(progressValueChanged(int)), &progressDialog, SLOT(setValue(int)));
    connect(&watcher, SIGNAL(progressRangeChanged(int, int)), &progressDialog, SLOT(setRange(int,int)));
    connect(&watcher, SIGNAL(progressValueChanged(int)), ui->progressBar, SLOT(setValue(int)));
    connect(&watcher, SIGNAL(progressRangeChanged(int, int)), ui->progressBar, SLOT(setRange(int,int)));
    connect(&watcher, SIGNAL(finished()), &progressDialog, SLOT(reset()));
    connect(&progressDialog, SIGNAL(canceled()), &watcher, SLOT(cancel()));

    connect(&watcher, SIGNAL(started()), this, SLOT(processStarted()));
    connect(&watcher, SIGNAL(finished()), this, SLOT(processFinished()));

    //Gets the list filled
    for (int i = 0; i < ui->listTreeWidget->topLevelItemCount(); i++) {
        list.append(ui->listTreeWidget->topLevelItem(i));
    }

    //And start
    watcher.setFuture(QtConcurrent::map(list, processRoutine));

    //Show the dialog
    progressDialog.exec();

}

extern void processRoutine(QTreeWidgetItem* item) {
    qDebug() << item->text(4);
}

I also added, in the UI (which holds all the previous widgets), a QProgressBar with the same SIGNALS/SLOTS. Keeping the code like the previous works as expected: the progress dialog shows up, and the progress bar updates exactly as the dialog. Instead, if I comment the

//progressDialog.exec(); 

or I hide the dialog in some way, the process crashes (not always, sometimes it goes well). Looking at qDebug() << item->text(4); it crashes and the output shows randomly mixed text (they are supposed to be filenames). Also, the progressbar does not update itself when the QProgressDialog is not shown, even if the computation does not crash.

Note: I experienced a similar problem before in another function, and I solved it by setting

QThreadPool::globalInstance()->setMaxThreadCount(1);

on Windows only, OSX was ok.

So, what's the trick behind the QProgressDialog that makes all the things right? Is there a way I can use the QProgressBar instead of the QProgressDialog?

NOTE

This is the output when the process completes without troubles:

"C:/Users/Utente/Pictures/Originals/unsplash_52cee67a5c618_1.jpg"
"C:/Users/Utente/Pictures/Originals/photo-1428278953961-a8bc45e05f72.jpg"
"C:/Users/Utente/Pictures/Originals/photo-1429152937938-07b5f2828cdd.jpg"
"C:/Users/Utente/Pictures/Originals/photo-1429277158984-614d155e0017.jpg"
"C:/Users/Utente/Pictures/Originals/photo-1430598825529-927d770c194f.jpg"
"C:/Users/Utente/Pictures/Originals/photo-1433838552652-f9a46b332c40.jpg"
Lymphatus
  • 336
  • 4
  • 6

1 Answers1

1

When you comment progressDialog.exec(); your on_actionButton_triggered() function finishes with destroying progressDialog so your signals are using pointers to nowhere. Also watcher is being destroyed too before or after all mapping is performed, and afair it does not stop threads so they also working with nowhere.

Ilya
  • 4,583
  • 4
  • 26
  • 51
Jerry
  • 143
  • 4