Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use the threads to create the images thumbnail

I'm use QTreeView to get the images path, then I'm use QListView to display the images that in specific path as thumbnail.

The problem in the period, create and display the thumbnail images.
The previous process, take a long time to done, depend on the number of images.
And for that reason I decided to use the threads, maybe helps to prevent the hung up which occur in application and increase the speed of create and display the thumbnail images.

void mainWidget::on_treeView_clicked(const QModelIndex &index){
    filesModel->clear();
    QFileSystemModel *sysModel = qobject_cast<QFileSystemModel*>(ui->treeView->model());
    QDir dir(sysModel->filePath(ui->treeView->currentIndex()));
    QFileInfoList filesList = dir.entryInfoList(QStringList() << "*.jpg" << "*.jpeg" << "*.tif" << "*.png" << "*.gif" << "*.bmp" ,QDir::Files);
    int filesCount = filesList.size();
    for(int i=0;i<filesCount;i++){
        QPixmap originalImage(filesList[i].filePath());
        if(!originalImage.isNull()){
            QPixmap scaledImage = originalImage.scaled(150, 120);    
            filesModel->setItem(i, new QStandardItem(QIcon(scaledImage), filesList[i].baseName()));
        }
    }
}

How can I use threads with the previous code ?

like image 677
Lion King Avatar asked Sep 29 '22 10:09

Lion King


2 Answers

I believe that a simple and correct approach is using QtConcurrent as the following:

Note: If you are using Qt 5 you will need to add QT += concurrent to the .pro file.

Header:

#include <QtCore>
#include <QtGui>
#include <QtWidgets>
#include <QtConcurrent>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

signals:
    void UpdateItem(int, QImage);

private slots:
    void on_treeView_clicked(const QModelIndex &);
    void List(QFileInfoList filesList, QSize size);
    void setThumbs(int index, QImage img);

private:
    Ui::MainWindow *ui;
    QFileSystemModel *model;
    QStandardItemModel *filesmodel;
    QFuture<void> thread;
    bool running;
};

CPP file:

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

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

    model = new QFileSystemModel(this);
    model->setRootPath("\\");

    filesmodel = new QStandardItemModel(this);

    ui->treeView->setModel(model);
    ui->listView->setModel(filesmodel);

    connect(this, SIGNAL(UpdateItem(int,QImage)), SLOT(setThumbs(int,QImage)));

    ui->treeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);

    running = false;
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_treeView_clicked(const QModelIndex&)
{
    filesmodel->clear();

    running = false;

    thread.waitForFinished();

    QDir dir(model->filePath(ui->treeView->currentIndex()));

    QFileInfoList filesList = dir.entryInfoList(QStringList() << "*.jpg" << "*.jpeg" << "*.tif" << "*.png" << "*.gif" << "*.bmp", QDir::Files);

    int filesCount = filesList.size();

    QPixmap placeholder = QPixmap(ui->listView->iconSize());
    placeholder.fill(Qt::gray);

    for (int i = 0; i < filesCount; i++)
        filesmodel->setItem(i, new QStandardItem(QIcon(placeholder), filesList[i].baseName()));

    running = true;

    thread = QtConcurrent::run(this, &MainWindow::List, filesList, ui->listView->iconSize());
}

void MainWindow::List(QFileInfoList filesList, QSize size)
{
    int filesCount = filesList.size();

    for (int i = 0; running && i < filesCount; i++)
    {
        QImage originalImage(filesList[i].filePath());
        if (!originalImage.isNull())
        {
            QImage scaledImage = originalImage.scaled(size);
            if (!running) return;
            emit UpdateItem(i, scaledImage);
        }
    }
}

void MainWindow::setThumbs(int index, QImage img)
{
    QIcon icon = QIcon(QPixmap::fromImage(img));
    QStandardItem *item = filesmodel->item(index);
    filesmodel->setItem(index, new QStandardItem(icon, item->text()));
}
like image 58
Antonio Dias Avatar answered Oct 03 '22 04:10

Antonio Dias


You don't have to use threads to keep your application responsive in this case. Use QCoreApplication::processEvents() in the loop to keep the application responsive. QCoreApplication::processEvents() will process all the events in the event queue of the thread which calls it.

like image 33
user1415913 Avatar answered Oct 03 '22 05:10

user1415913