commit 6fcd6c90
Try to load the images a little more dynamic. Does not really work at the moment as the current icon field just gives everything every time
Changed files
| M | imagemodel.cpp before |
| M | imagemodel.h before |
| M | mainwindow.cpp before |
| M | mainwindow.h before |
| M | thumbnailworker.cpp before |
| M | thumbnailworker.h before |
diff --git a/imagemodel.cpp b/imagemodel.cpp
index b6fd272..5c58083 100644
--- a/imagemodel.cpp
+++ b/imagemodel.cpp
@@ -10,20 +10,25 @@ ImageModel::ImageModel(QObject *parent)
{
m_threadPool.setMaxThreadCount(QThread::idealThreadCount());
- // Simple gray placeholder
m_placeholder = QPixmap(128, 128);
m_placeholder.fill(Qt::lightGray);
}
ImageModel::~ImageModel()
{
+ m_cancelFlag = true;
m_threadPool.waitForDone();
}
void ImageModel::setDirectory(const QString &path)
{
+ m_cancelFlag = true;
+ m_threadPool.waitForDone();
+ m_cancelFlag = false;
+
beginResetModel();
m_items.clear();
+ m_pendingRows.clear();
QDir dir(path);
QStringList filters;
@@ -37,24 +42,56 @@ void ImageModel::setDirectory(const QString &path)
const auto files = dir.entryInfoList();
- int row = 0;
for (const QFileInfo &file : files)
{
m_items.append({file.absoluteFilePath(), m_placeholder, false});
+ }
- // Create worker
- auto *worker = new ThumbnailWorker(file.absoluteFilePath(), row);
+ endResetModel();
+}
- connect(worker, &ThumbnailWorker::finished,
- this, &ImageModel::thumbnailReady,
- Qt::QueuedConnection);
+void ImageModel::requestThumbnails(int firstRow, int lastRow)
+{
+ if (m_items.isEmpty())
+ return;
- m_threadPool.start(worker);
+ firstRow = std::max(0, firstRow);
+ lastRow = std::min(lastRow, static_cast<int>(m_items.size()) - 1);
- row++;
+ for (int row = firstRow; row <= lastRow; ++row)
+ {
+ if (!m_items[row].loaded)
+ queueRow(row);
}
- endResetModel();
+ // Optional: preload nearby rows
+ int buffer = 20;
+ for (int row = firstRow - buffer; row < firstRow; ++row)
+ if (row >= 0 && !m_items[row].loaded)
+ queueRow(row);
+
+ for (int row = lastRow + 1; row <= lastRow + buffer; ++row)
+ if (row < m_items.size() && !m_items[row].loaded)
+ queueRow(row);
+}
+
+void ImageModel::queueRow(int row)
+{
+ if (m_pendingRows.contains(row))
+ return;
+
+ m_pendingRows.insert(row);
+
+ auto *worker = new ThumbnailWorker(
+ m_items[row].path,
+ row,
+ &m_cancelFlag);
+
+ connect(worker, &ThumbnailWorker::finished,
+ this, &ImageModel::thumbnailReady,
+ Qt::QueuedConnection);
+
+ m_threadPool.start(worker);
}
QString ImageModel::filePath(const QModelIndex &index) const
@@ -86,13 +123,17 @@ QVariant ImageModel::data(const QModelIndex &index, int role) const
return {};
}
-void ImageModel::thumbnailReady(int row, const QPixmap &pixmap)
+void ImageModel::thumbnailReady(int row, const QImage &image)
{
+ if (m_cancelFlag)
+ return;
+
if (row < 0 || row >= m_items.size())
return;
- m_items[row].thumbnail = pixmap;
+ m_items[row].thumbnail = QPixmap::fromImage(image);
m_items[row].loaded = true;
+ m_pendingRows.remove(row);
QModelIndex idx = index(row);
emit dataChanged(idx, idx, {Qt::DecorationRole});
diff --git a/imagemodel.h b/imagemodel.h
index ab11e6d..c124ae6 100644
--- a/imagemodel.h
+++ b/imagemodel.h
@@ -4,6 +4,8 @@
#include <QPixmap>
#include <QVector>
#include <QThreadPool>
+#include <QSet>
+#include <atomic>
class ThumbnailWorker;
@@ -18,10 +20,12 @@ public:
void setDirectory(const QString &path);
QString filePath(const QModelIndex &index) const;
+ void requestThumbnails(int firstRow, int lastRow);
+
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role) const override;
- void thumbnailReady(int row, const QPixmap &pixmap);
+ void thumbnailReady(int row, const QImage &image);
private:
struct Item
@@ -31,7 +35,12 @@ private:
bool loaded = false;
};
+ void queueRow(int row);
+
QVector<Item> m_items;
QThreadPool m_threadPool;
QPixmap m_placeholder;
+
+ QSet<int> m_pendingRows;
+ std::atomic_bool m_cancelFlag{false};
};
diff --git a/mainwindow.cpp b/mainwindow.cpp
index a724b32..fedb644 100644
--- a/mainwindow.cpp
+++ b/mainwindow.cpp
@@ -9,6 +9,10 @@
#include <QDir>
#include <QImageReader>
#include <QHeaderView>
+#include <QScrollBar>
+#include <QTimer>
+#include <QEvent>
+#include <iostream>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
@@ -67,24 +71,59 @@ void MainWindow::setupConnections()
{
connect(m_treeView, &QTreeView::clicked, this,
[this](const QModelIndex &index)
- {
- QString path = m_dirModel->filePath(index);
- m_imageModel->setDirectory(path);
- });
+ {
+ QString path = m_dirModel->filePath(index);
+ m_imageModel->setDirectory(path);
+ // Defer thumbnail load so the view has time to lay out items
+ QTimer::singleShot(0, this, &MainWindow::loadVisibleThumbnails);
+ });
connect(m_listView, &QListView::clicked, this,
[this](const QModelIndex &index)
- {
- QString path = m_imageModel->filePath(index);
-
- QImageReader reader(path);
- reader.setAutoTransform(true);
- QImage image = reader.read();
-
- m_previewLabel->setPixmap(
- QPixmap::fromImage(image).scaled(
- m_previewLabel->size(),
- Qt::KeepAspectRatio,
- Qt::SmoothTransformation));
- });
+ {
+ QString path = m_imageModel->filePath(index);
+
+ QImageReader reader(path);
+ reader.setAutoTransform(true);
+ QImage image = reader.read();
+
+ m_previewLabel->setPixmap(
+ QPixmap::fromImage(image).scaled(
+ m_previewLabel->size(),
+ Qt::KeepAspectRatio,
+ Qt::SmoothTransformation));
+ });
+
+ connect(m_listView->verticalScrollBar(), &QScrollBar::valueChanged,
+ this, [this]()
+ { loadVisibleThumbnails(); });
+
+ // Also catch resize — visible range changes when the viewport is resized
+ m_listView->viewport()->installEventFilter(this);
+}
+
+bool MainWindow::eventFilter(QObject *obj, QEvent *event)
+{
+ if (obj == m_listView->viewport() && event->type() == QEvent::Resize)
+ QTimer::singleShot(0, this, &MainWindow::loadVisibleThumbnails);
+
+ return QMainWindow::eventFilter(obj, event);
+}
+
+void MainWindow::loadVisibleThumbnails()
+{
+ QModelIndex topLeft = m_listView->indexAt(QPoint(0, 0));
+ QModelIndex bottomRight = m_listView->indexAt(
+ QPoint(m_listView->viewport()->width() - 1,
+ m_listView->viewport()->height() - 1));
+
+ int first = topLeft.isValid() ? topLeft.row() : 0;
+ int last = bottomRight.isValid() ? bottomRight.row()
+ : m_imageModel->rowCount() - 1;
+
+ if (last < 0)
+ return;
+
+ std::cout << "loadVisibleThumbnails: " << first << " - " << last << "\n";
+ m_imageModel->requestThumbnails(first, last);
}
diff --git a/mainwindow.h b/mainwindow.h
index 43ecfe2..f801f66 100644
--- a/mainwindow.h
+++ b/mainwindow.h
@@ -18,6 +18,9 @@ public:
private:
void setupUi();
void setupConnections();
+ void loadVisibleThumbnails();
+
+ bool eventFilter(QObject *obj, QEvent *event) override;
QFileSystemModel *m_dirModel;
ImageModel *m_imageModel;
diff --git a/thumbnailworker.cpp b/thumbnailworker.cpp
index f02d710..25152d5 100644
--- a/thumbnailworker.cpp
+++ b/thumbnailworker.cpp
@@ -1,27 +1,34 @@
#include "thumbnailworker.h"
#include <QImageReader>
-ThumbnailWorker::ThumbnailWorker(const QString &path, int row)
- : m_path(path), m_row(row)
+ThumbnailWorker::ThumbnailWorker(const QString &path,
+ int row,
+ std::atomic_bool *cancelFlag)
+ : m_path(path),
+ m_row(row),
+ m_cancelFlag(cancelFlag)
{
setAutoDelete(true);
}
void ThumbnailWorker::run()
{
+ if (*m_cancelFlag)
+ return;
+
QImageReader reader(m_path);
reader.setAutoTransform(true);
QImage image = reader.read();
- QPixmap thumb;
+
+ if (*m_cancelFlag)
+ return;
if (!image.isNull())
{
- thumb = QPixmap::fromImage(
- image.scaled(128, 128,
- Qt::KeepAspectRatio,
- Qt::SmoothTransformation));
+ QImage thumb = image.scaled(128, 128,
+ Qt::KeepAspectRatio,
+ Qt::SmoothTransformation);
+ emit finished(m_row, thumb);
}
-
- emit finished(m_row, thumb);
}
diff --git a/thumbnailworker.h b/thumbnailworker.h
index 13df897..5cdb7cd 100644
--- a/thumbnailworker.h
+++ b/thumbnailworker.h
@@ -2,21 +2,25 @@
#include <QRunnable>
#include <QObject>
-#include <QPixmap>
+#include <QImage>
+#include <atomic>
class ThumbnailWorker : public QObject, public QRunnable
{
Q_OBJECT
public:
- ThumbnailWorker(const QString &path, int row);
+ ThumbnailWorker(const QString &path,
+ int row,
+ std::atomic_bool *cancelFlag);
void run() override;
signals:
- void finished(int row, const QPixmap &pixmap);
+ void finished(int row, const QImage &image);
private:
QString m_path;
int m_row;
+ std::atomic_bool *m_cancelFlag;
};