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 <QFile>
#include <QFileInfo> #include <QFileInfo>
#include <QIcon> #include <QIcon>
#include <QImage>
#include <QJsonArray>
#include <QJsonDocument> #include <QJsonDocument>
#include <QJsonObject> #include <QJsonObject>
#include <QPixmap> #include <QPixmap>
#include <QtConcurrent>
ArtModel::ArtModel(const QString& definitionDirectory, const QString& assetDirectory) : QAbstractTableModel() { 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); QDirIterator it(definitionDirectory);
while (it.hasNext()) { while (it.hasNext()) {
QFileInfo info(it.next()); QFileInfo info(it.next());
@ -18,22 +26,26 @@ ArtModel::ArtModel(const QString& definitionDirectory, const QString& assetDirec
continue; 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); beginInsertRows(QModelIndex(), m_artPieces.size(), m_artPieces.size() + 1);
ArtPiece p; m_artPieces.push_back(ArtPiece{});
loadData(p, QString("%1/%2").arg(definitionDirectory).arg(info.baseName()), QString("%1/%2").arg(assetDirectory).arg(info.baseName()));
m_artPieces.push_back(p);
endInsertRows(); endInsertRows();
} }
std::sort(m_artPieces.begin(), m_artPieces.end(), [](ArtPiece& a, ArtPiece& b) std::function<ArtPiece(const PieceInformation& info)> loadPiece = [this](const PieceInformation& info) -> ArtPiece {
{ ArtPiece p;
return a.date > b.date; 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 { int ArtModel::rowCount(const QModelIndex &parent) const {
@ -65,10 +77,7 @@ QVariant ArtModel::data(const QModelIndex &index, int role) const {
switch(index.column()) { switch(index.column()) {
case 1: case 1:
{ {
QImage image; return m_artPieces[index.row()].thumbnail;
image.load(m_artPieces[index.row()].filename);
return QPixmap::fromImage(image).scaled(100, 100, Qt::AspectRatioMode::KeepAspectRatio);
} }
break; break;
case 3: case 3:
@ -113,7 +122,25 @@ void ArtModel::loadData(ArtPiece& piece, const QString& filename, const QString&
piece.date = QDate::fromString(artJson["date"].toString(), "yyyy"); 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")) { if(artJson.object().contains("alt_text")) {
piece.hasAltText = true; 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 #pragma once
#include <QAbstractTableModel> #include <QAbstractTableModel>
#include <QImage>
#include <QJsonObject> #include <QJsonObject>
#include <QFutureWatcher>
struct ArtPiece { struct ArtPiece {
QString filename, jsonFilename; QString filename, jsonFilename;
@ -9,6 +11,7 @@ struct ArtPiece {
QJsonObject object; QJsonObject object;
QDate date; QDate date;
QImage image, thumbnail;
bool hasAltText = false; bool hasAltText = false;
}; };
@ -26,5 +29,10 @@ public:
private: private:
void loadData(ArtPiece& piece, const QString& filename, const QString& assetFilename); void loadData(ArtPiece& piece, const QString& filename, const QString& assetFilename);
void pieceFinished(int index);
void finished();
QFutureWatcher<ArtPiece>* piecesFuture;
QList<ArtPiece> m_artPieces; QList<ArtPiece> m_artPieces;
}; };

View file

@ -10,6 +10,7 @@ find_package(Qt5 COMPONENTS
Core Core
Gui Gui
Widgets Widgets
Concurrent
REQUIRED) REQUIRED)
add_executable(Redai main.cpp MainWindow.cpp MainWindow.h ArtModel.cpp ArtModel.h ArtDetailWindow.cpp ArtDetailWindow.h imagelabel.cpp imagelabel.h) 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::Core
Qt5::Gui Qt5::Gui
Qt5::Widgets Qt5::Widgets
Qt5::Concurrent
) )