diff --git a/CMakeLists.txt b/CMakeLists.txt index ea1e767..3eba63e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,8 @@ qt_add_executable(ImageBrowser mainwindow.h imagemodel.cpp imagemodel.h + thumbnailworker.cpp + thumbnailworker.h ) target_link_libraries(ImageBrowser PRIVATE Qt6::Widgets) \ No newline at end of file diff --git a/imagemodel.cpp b/imagemodel.cpp index f22f119..b6fd272 100644 --- a/imagemodel.cpp +++ b/imagemodel.cpp @@ -1,4 +1,5 @@ #include "imagemodel.h" +#include "thumbnailworker.h" #include #include @@ -7,6 +8,16 @@ ImageModel::ImageModel(QObject *parent) : QAbstractListModel(parent) { + m_threadPool.setMaxThreadCount(QThread::idealThreadCount()); + + // Simple gray placeholder + m_placeholder = QPixmap(128, 128); + m_placeholder.fill(Qt::lightGray); +} + +ImageModel::~ImageModel() +{ + m_threadPool.waitForDone(); } void ImageModel::setDirectory(const QString &path) @@ -24,17 +35,23 @@ void ImageModel::setDirectory(const QString &path) dir.setNameFilters(filters); dir.setFilter(QDir::Files); - for (const QFileInfo &file : dir.entryInfoList()) + const auto files = dir.entryInfoList(); + + int row = 0; + for (const QFileInfo &file : files) { - QImageReader reader(file.absoluteFilePath()); - reader.setAutoTransform(true); + m_items.append({file.absoluteFilePath(), m_placeholder, false}); + + // Create worker + auto *worker = new ThumbnailWorker(file.absoluteFilePath(), row); - QImage image = reader.read(); - QPixmap thumb = QPixmap::fromImage( - image.scaled(128, 128, Qt::KeepAspectRatio, - Qt::SmoothTransformation)); + connect(worker, &ThumbnailWorker::finished, + this, &ImageModel::thumbnailReady, + Qt::QueuedConnection); - m_items.append({file.absoluteFilePath(), thumb}); + m_threadPool.start(worker); + + row++; } endResetModel(); @@ -68,3 +85,15 @@ QVariant ImageModel::data(const QModelIndex &index, int role) const return {}; } + +void ImageModel::thumbnailReady(int row, const QPixmap &pixmap) +{ + if (row < 0 || row >= m_items.size()) + return; + + m_items[row].thumbnail = pixmap; + m_items[row].loaded = true; + + QModelIndex idx = index(row); + emit dataChanged(idx, idx, {Qt::DecorationRole}); +} diff --git a/imagemodel.h b/imagemodel.h index 3915a94..ab11e6d 100644 --- a/imagemodel.h +++ b/imagemodel.h @@ -3,6 +3,9 @@ #include #include #include +#include + +class ThumbnailWorker; class ImageModel : public QAbstractListModel { @@ -10,6 +13,7 @@ class ImageModel : public QAbstractListModel public: explicit ImageModel(QObject *parent = nullptr); + ~ImageModel(); void setDirectory(const QString &path); QString filePath(const QModelIndex &index) const; @@ -17,12 +21,17 @@ public: int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role) const override; + void thumbnailReady(int row, const QPixmap &pixmap); + private: struct Item { QString path; QPixmap thumbnail; + bool loaded = false; }; QVector m_items; + QThreadPool m_threadPool; + QPixmap m_placeholder; }; diff --git a/thumbnailworker.cpp b/thumbnailworker.cpp new file mode 100644 index 0000000..f02d710 --- /dev/null +++ b/thumbnailworker.cpp @@ -0,0 +1,27 @@ +#include "thumbnailworker.h" +#include + +ThumbnailWorker::ThumbnailWorker(const QString &path, int row) + : m_path(path), m_row(row) +{ + setAutoDelete(true); +} + +void ThumbnailWorker::run() +{ + QImageReader reader(m_path); + reader.setAutoTransform(true); + + QImage image = reader.read(); + QPixmap thumb; + + if (!image.isNull()) + { + thumb = QPixmap::fromImage( + image.scaled(128, 128, + Qt::KeepAspectRatio, + Qt::SmoothTransformation)); + } + + emit finished(m_row, thumb); +} diff --git a/thumbnailworker.h b/thumbnailworker.h new file mode 100644 index 0000000..13df897 --- /dev/null +++ b/thumbnailworker.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include +#include + +class ThumbnailWorker : public QObject, public QRunnable +{ + Q_OBJECT + +public: + ThumbnailWorker(const QString &path, int row); + + void run() override; + +signals: + void finished(int row, const QPixmap &pixmap); + +private: + QString m_path; + int m_row; +};