如何使用线程来创建图像缩略图

时间:2014-11-09 15:22:06

标签: c++ multithreading qt qt5

我使用QTreeView来获取图片路径,然后我使用QListView将特定路径中的图片显示为缩略图。

期间的问题,创建并显示缩略图图像 上一个过程,需要很长时间才能完成,取决于图像的数量 因此我决定使用线程,可能有助于防止应用程序中出现挂起并提高创建和显示缩略图图像的速度。

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()));
        }
    }
}

如何使用前一代码的线程?

3 个答案:

答案 0 :(得分:2)

我认为一种简单而正确的方法是使用QtConcurrent作为以下内容:

注意:如果您使用的是Qt 5,则需要将QT += concurrent添加到.pro文件中。

部首:

#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文件:

#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()));
}

答案 1 :(得分:1)

在这种情况下,您不必使用线程来保持应用程序的响应能力。在循环中使用QCoreApplication::processEvents()可以使应用程序保持响应。 QCoreApplication::processEvents()将处理调用它的线程的事件队列中的所有事件。

答案 2 :(得分:0)

这是一个较旧的主题,但仍会出现在Google中。查看this related question的答案。我发现QIdentityProxyModel的使用更加优雅,因为它允许QFileSystemModel用作列表视图的模型。