git repos / SagoImageBrowser

commit 032aa1e1

Poul Sander · 2026-02-19 18:55
032aa1e161c4fd5d6a7554d65109e9a069648a17 patch · browse files

Initial commit

Changed files

A CMakeLists.txt
A imagemodel.cpp
A imagemodel.h
A main.cpp
A mainwindow.cpp
A mainwindow.h
diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..ea1e767 --- /dev/null +++ b/CMakeLists.txt
@@ -0,0 +1,17 @@
+cmake_minimum_required(VERSION 3.21)
+project(ImageBrowser LANGUAGES CXX)
+
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_AUTOMOC ON)
+
+find_package(Qt6 REQUIRED COMPONENTS Widgets)
+
+qt_add_executable(ImageBrowser
+ main.cpp
+ mainwindow.cpp
+ mainwindow.h
+ imagemodel.cpp
+ imagemodel.h
+)
+
+target_link_libraries(ImageBrowser PRIVATE Qt6::Widgets)
\ No newline at end of file
diff --git a/imagemodel.cpp b/imagemodel.cpp new file mode 100644 index 0000000..f22f119 --- /dev/null +++ b/imagemodel.cpp
@@ -0,0 +1,70 @@
+#include "imagemodel.h"
+
+#include <QDir>
+#include <QImageReader>
+#include <QFileInfo>
+
+ImageModel::ImageModel(QObject *parent)
+ : QAbstractListModel(parent)
+{
+}
+
+void ImageModel::setDirectory(const QString &path)
+{
+ beginResetModel();
+ m_items.clear();
+
+ QDir dir(path);
+ QStringList filters;
+
+ const auto formats = QImageReader::supportedImageFormats();
+ for (const QByteArray &fmt : formats)
+ filters << "*." + fmt;
+
+ dir.setNameFilters(filters);
+ dir.setFilter(QDir::Files);
+
+ for (const QFileInfo &file : dir.entryInfoList())
+ {
+ QImageReader reader(file.absoluteFilePath());
+ reader.setAutoTransform(true);
+
+ QImage image = reader.read();
+ QPixmap thumb = QPixmap::fromImage(
+ image.scaled(128, 128, Qt::KeepAspectRatio,
+ Qt::SmoothTransformation));
+
+ m_items.append({file.absoluteFilePath(), thumb});
+ }
+
+ endResetModel();
+}
+
+QString ImageModel::filePath(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return {};
+
+ return m_items[index.row()].path;
+}
+
+int ImageModel::rowCount(const QModelIndex &) const
+{
+ return m_items.size();
+}
+
+QVariant ImageModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return {};
+
+ const Item &item = m_items[index.row()];
+
+ if (role == Qt::DecorationRole)
+ return item.thumbnail;
+
+ if (role == Qt::DisplayRole)
+ return QFileInfo(item.path).fileName();
+
+ return {};
+}
diff --git a/imagemodel.h b/imagemodel.h new file mode 100644 index 0000000..3915a94 --- /dev/null +++ b/imagemodel.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include <QAbstractListModel>
+#include <QPixmap>
+#include <QVector>
+
+class ImageModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+public:
+ explicit ImageModel(QObject *parent = nullptr);
+
+ void setDirectory(const QString &path);
+ QString filePath(const QModelIndex &index) const;
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ QVariant data(const QModelIndex &index, int role) const override;
+
+private:
+ struct Item
+ {
+ QString path;
+ QPixmap thumbnail;
+ };
+
+ QVector<Item> m_items;
+};
diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..6ce4d29 --- /dev/null +++ b/main.cpp
@@ -0,0 +1,13 @@
+#include <QApplication>
+#include "mainwindow.h"
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+
+ MainWindow w;
+ w.resize(1200, 700);
+ w.show();
+
+ return app.exec();
+}
diff --git a/mainwindow.cpp b/mainwindow.cpp new file mode 100644 index 0000000..a724b32 --- /dev/null +++ b/mainwindow.cpp
@@ -0,0 +1,90 @@
+#include "mainwindow.h"
+#include "imagemodel.h"
+
+#include <QFileSystemModel>
+#include <QTreeView>
+#include <QListView>
+#include <QLabel>
+#include <QSplitter>
+#include <QDir>
+#include <QImageReader>
+#include <QHeaderView>
+
+MainWindow::MainWindow(QWidget *parent)
+ : QMainWindow(parent)
+{
+ setupUi();
+ setupConnections();
+}
+
+void MainWindow::setupUi()
+{
+ // Folder model (left pane)
+ m_dirModel = new QFileSystemModel(this);
+ m_dirModel->setFilter(QDir::AllDirs | QDir::NoDotAndDotDot);
+ m_dirModel->setRootPath(QDir::homePath());
+
+ m_treeView = new QTreeView;
+ m_treeView->setModel(m_dirModel);
+ m_treeView->setRootIndex(m_dirModel->index(QDir::homePath()));
+ m_treeView->header()->hide();
+ m_treeView->setColumnHidden(1, true);
+ m_treeView->setColumnHidden(2, true);
+ m_treeView->setColumnHidden(3, true);
+
+ // Thumbnail model (center pane)
+ m_imageModel = new ImageModel(this);
+
+ m_listView = new QListView;
+ m_listView->setModel(m_imageModel);
+ m_listView->setViewMode(QListView::IconMode);
+ m_listView->setIconSize(QSize(128, 128));
+ m_listView->setResizeMode(QListView::Adjust);
+ m_listView->setSelectionMode(QAbstractItemView::SingleSelection);
+ m_listView->setSpacing(10);
+
+ // Preview pane (right)
+ m_previewLabel = new QLabel;
+ m_previewLabel->setAlignment(Qt::AlignCenter);
+ m_previewLabel->setMinimumWidth(300);
+
+ // Layout
+ QSplitter *rightSplitter = new QSplitter(Qt::Horizontal);
+ rightSplitter->addWidget(m_listView);
+ rightSplitter->addWidget(m_previewLabel);
+ rightSplitter->setStretchFactor(0, 3);
+ rightSplitter->setStretchFactor(1, 2);
+
+ QSplitter *mainSplitter = new QSplitter(Qt::Horizontal);
+ mainSplitter->addWidget(m_treeView);
+ mainSplitter->addWidget(rightSplitter);
+ mainSplitter->setStretchFactor(1, 1);
+
+ setCentralWidget(mainSplitter);
+}
+
+void MainWindow::setupConnections()
+{
+ connect(m_treeView, &QTreeView::clicked, this,
+ [this](const QModelIndex &index)
+ {
+ QString path = m_dirModel->filePath(index);
+ m_imageModel->setDirectory(path);
+ });
+
+ 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));
+ });
+}
diff --git a/mainwindow.h b/mainwindow.h new file mode 100644 index 0000000..43ecfe2 --- /dev/null +++ b/mainwindow.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include <QMainWindow>
+
+class QTreeView;
+class QListView;
+class QLabel;
+class QFileSystemModel;
+class ImageModel;
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ explicit MainWindow(QWidget *parent = nullptr);
+
+private:
+ void setupUi();
+ void setupConnections();
+
+ QFileSystemModel *m_dirModel;
+ ImageModel *m_imageModel;
+
+ QTreeView *m_treeView;
+ QListView *m_listView;
+ QLabel *m_previewLabel;
+};