qtqtconcurrentqfuture

Problems developing QFutureWatcher to improve image loading times


I am trying to load multiple images using multithreading through QFutureWatcher class but I am not being able to do it properly. My code read the url of the images and save them on a QVector. Then I Pass these QStrings to a function that load, resize and save the images on a QMap object. The code is:

    void MainWindow::loadImages(){
             mImagesLoaderfutureWatcher = new QFutureWatcher<QString>() ;
        connect(mImagesLoaderfutureWatcher, SIGNAL(finished()),this, SLOT(imageLoadingfinished()));

        QVector<QString> imagesList = mProject->getImagesFileName();

        // Start the computation.
        mImagesLoaderfutureWatcher->setFuture(QtConcurrent::map(imagesList,addImageThumnailToMap));
}

    void MainWindow::addImageThumnailToMap(QString imageName){
        QSize desiredSize(100,100);
        QImage orig(mProject->getBasePath()+"/"+imageName);
        QImage scaled = orig.scaled(
                    desiredSize,
                    Qt::KeepAspectRatio,
                    Qt::SmoothTransformation);

        mMapImages->insert(imageName,scaled);
    }

    void MainWindow::imageLoadingfinished(){
        QMessageBox msg;
        msg.setText("Images loaded");
        msg.show();
    }

The error that I am receiving when I try to compile said that the list of arguments in the call to the function "addImageThumnailToMap" is not found but I think that it is not neccesary specify that on the "QtConcurrent::map()" function. Thanks for your help


Solution

  • It's because the function is a member of a class. You should call it like this:

    mImagesLoaderfutureWatcher->setFuture(
       QtConcurrent::map(imagesList,&MainWindow::addImageThumnailToMap));
    

    It also looks like QtConcurrent::map takes only global functions or static functions, because there is no pointer to instance to call addImageThumnailToMap. So declear MainWindow::addImageThumnailToMap as static.

    I personally prefer to use QtConcurrent::run, which can handle class member functions. E.g:

    void ImageGroupView::setImages( QStringList il )
    {
        //QFuture<int> _imageLoader;    
        //QFutureWatcher<int> _watcher;
        _imageLoader = QtConcurrent::run(this, &ImageGroupView::loadImages, il );   
        connect(&_watcher, SIGNAL(finished()), this, SLOT(processImagesReady()));
        _watcher.setFuture( _imageLoader );
    }
    

    The template parameters just happened to be int, because the function loadImages returns the number of actually loaded images.

    int ImageGroupView::loadImages( QStringList il )
    {
        int numLoaded=0;
        _images.clear();
        foreach ( QString img, il )
        {
            if( QFileInfo( img ).exists() )
            {
                _imageList.append( QImage( img ).scaled(640,480) );
                numLoaded++;
            }
        }
        return numLoaded;
    }