Concurrently load thumbnail images, improving startup times

This commit is contained in:
Joshua Goins 2023-06-15 13:54:18 -04:00
parent 861a8a14f2
commit ad37574be9
3 changed files with 53 additions and 16 deletions

View file

@ -4,13 +4,21 @@
#include <QFile>
#include <QFileInfo>
#include <QIcon>
#include <QImage>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QPixmap>
#include <QtConcurrent>
ArtModel::ArtModel(const QString& definitionDirectory, const QString& assetDirectory) : QAbstractTableModel() {
piecesFuture = new QFutureWatcher<ArtPiece>(this);
connect(piecesFuture, &QFutureWatcher<ArtPiece>::resultReadyAt, this, &ArtModel::pieceFinished);
connect(piecesFuture, &QFutureWatcher<ArtPiece>::finished, this, &ArtModel::finished);
struct PieceInformation {
QString definition;
QString asset;
};
QVector<PieceInformation> pieceList;
QDirIterator it(definitionDirectory);
while (it.hasNext()) {
QFileInfo info(it.next());
@ -18,22 +26,26 @@ ArtModel::ArtModel(const QString& definitionDirectory, const QString& assetDirec
continue;
}
pieceList.push_back(PieceInformation{QString("%1/%2").arg(definitionDirectory).arg(info.baseName()), QString("%1/%2").arg(assetDirectory).arg(info.baseName())});
beginInsertRows(QModelIndex(), m_artPieces.size(), m_artPieces.size() + 1);
ArtPiece p;
loadData(p, QString("%1/%2").arg(definitionDirectory).arg(info.baseName()), QString("%1/%2").arg(assetDirectory).arg(info.baseName()));
m_artPieces.push_back(p);
m_artPieces.push_back(ArtPiece{});
endInsertRows();
}
std::sort(m_artPieces.begin(), m_artPieces.end(), [](ArtPiece& a, ArtPiece& b)
{
return a.date > b.date;
});
std::function<ArtPiece(const PieceInformation& info)> loadPiece = [this](const PieceInformation& info) -> ArtPiece {
ArtPiece p;
loadData(p, info.definition, info.asset);
dataChanged(index(0, 0), index(m_artPieces.size(), 0));
p.image.load(p.filename);
p.thumbnail = QPixmap::fromImage(p.image).scaled(100, 100, Qt::AspectRatioMode::KeepAspectRatio).toImage();
return p;
};
piecesFuture->setFuture(QtConcurrent::mapped(pieceList, loadPiece));
}
int ArtModel::rowCount(const QModelIndex &parent) const {
@ -65,10 +77,7 @@ QVariant ArtModel::data(const QModelIndex &index, int role) const {
switch(index.column()) {
case 1:
{
QImage image;
image.load(m_artPieces[index.row()].filename);
return QPixmap::fromImage(image).scaled(100, 100, Qt::AspectRatioMode::KeepAspectRatio);
return m_artPieces[index.row()].thumbnail;
}
break;
case 3:
@ -113,7 +122,25 @@ void ArtModel::loadData(ArtPiece& piece, const QString& filename, const QString&
piece.date = QDate::fromString(artJson["date"].toString(), "yyyy");
}
if (artJson.object().contains("title")) {
piece.title = artJson.object()["title"].toString();
}
if(artJson.object().contains("alt_text")) {
piece.hasAltText = true;
}
}
}
void ArtModel::pieceFinished(int row) {
m_artPieces[row] = piecesFuture->resultAt(row);
Q_EMIT dataChanged(index(row, 0), index(row + 1, 0));
}
void ArtModel::finished() {
std::sort(m_artPieces.begin(), m_artPieces.end(), [](ArtPiece& a, ArtPiece& b)
{
return a.date > b.date;
});
Q_EMIT dataChanged(index(0, 0), index(m_artPieces.size(), 0));
}

View file

@ -1,7 +1,9 @@
#pragma once
#include <QAbstractTableModel>
#include <QImage>
#include <QJsonObject>
#include <QFutureWatcher>
struct ArtPiece {
QString filename, jsonFilename;
@ -9,6 +11,7 @@ struct ArtPiece {
QJsonObject object;
QDate date;
QImage image, thumbnail;
bool hasAltText = false;
};
@ -26,5 +29,10 @@ public:
private:
void loadData(ArtPiece& piece, const QString& filename, const QString& assetFilename);
void pieceFinished(int index);
void finished();
QFutureWatcher<ArtPiece>* piecesFuture;
QList<ArtPiece> m_artPieces;
};

View file

@ -10,6 +10,7 @@ find_package(Qt5 COMPONENTS
Core
Gui
Widgets
Concurrent
REQUIRED)
add_executable(Redai main.cpp MainWindow.cpp MainWindow.h ArtModel.cpp ArtModel.h ArtDetailWindow.cpp ArtDetailWindow.h imagelabel.cpp imagelabel.h)
@ -17,5 +18,6 @@ target_link_libraries(Redai
Qt5::Core
Qt5::Gui
Qt5::Widgets
Qt5::Concurrent
)