gpt4 book ai didi

c++ - Qt中的图像浏览器

转载 作者:太空狗 更新时间:2023-10-29 21:20:23 24 4
gpt4 key购买 nike

下面的代码在左 Pane 中显示缩略图。单击缩略图时,全尺寸图像会出现在右侧 Pane 中。

image-browser

我的印象是,尽管这段代码相当简短,但它并不是在 Qt 中执行此任务的最自然方式。我是在重新发明轮子吗?是否有更适合此任务的模型 View 类?

// main.cpp
#include "PixmapPair.h"
#include <QLabel>
#include <QWidget>
#include <QApplication>
#include <QSplitter>
#include <QGridLayout>
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
QSplitter* page = new QSplitter;

QGridLayout* gridLayout = new QGridLayout;
QWidget* leftPane = new QWidget(page);
leftPane->setLayout(gridLayout);
QLabel* rightPane = new QLabel(page);
PixmapPair pair1(":/images/ocean.jpg", gridLayout, rightPane);
PixmapPair pair2(":/images/forest.jpg", gridLayout, rightPane);

page->setWindowTitle("Images");
page->show();
return app.exec();
}

// PixmapPair.h
#include <QPixmap>
#include <QIcon>
#include <QLabel>
#include <QPushButton>
#include <QGridLayout>
class PixmapPair : public QObject
{
Q_OBJECT
public:
PixmapPair(QString file, QGridLayout * gridLayout, QLabel* rp)
: rightPane(rp), largePixmap(file)
{
smallPixmap = largePixmap.scaled(QSize(100,100), Qt::KeepAspectRatio, Qt::SmoothTransformation);
QPushButton* pushButton = new QPushButton;
pushButton->setIcon(QIcon(smallPixmap));
pushButton->setFlat(true);
pushButton->setIconSize(QSize(100,100));
QObject::connect(pushButton, SIGNAL(clicked()), SLOT(displayInRightPane()));
gridLayout->addWidget(pushButton);
}
public slots:
void displayInRightPane()
{
rightPane->setPixmap(largePixmap);
}
private:
QLabel* rightPane;
QPixmap largePixmap;
QPixmap smallPixmap;
};

最佳答案

SplitView 的左侧部分基本上是一个显示所有可用图片的列表。 Qt 提供了一种使用模型/ View 模式来处理此问题的方法。

显示列表的类是 QListView,它将根据函数 setModel() 给定的模型自动完成这项工作。这个函数需要一个QAbstractItemModel,因为这个类是一个纯抽象类,我们需要创建一个派生自它的自定义类。
从它继承将需要大量的胶水代码,但幸运的是 Qt 已经提供了一个类,当我们想要表示一个列表时,它会处理大部分代码,它称为 QAbstractListModel

所以我创建了一个像这样的 ImageListModel :

///////////////////////  
// imagelistmodel.h ///
#ifndef IMAGELISTMODEL_H
#define IMAGELISTMODEL_H

#include <QAbstractListModel>
#include <QPixmap>

struct PixmapPair
{
QString _file;
QPixmap _small;
QPixmap _large;
};

class ImageListModel : public QAbstractListModel
{
Q_OBJECT
public:
// QAbstractItemModel retrieves various information (like text, color, ...)
// from the same index using roles. We can define custom ones, however to
// avoid a clash with predefined roles, ours must start at Qt::UserRole.
// All numbers below this one are reserved for Qt internals.
enum Roles
{
LargePixmapRole = Qt::UserRole + 1
};

explicit ImageListModel(std::initializer_list<QString> files, QObject *parent = 0);
virtual ~ImageListModel();

// QAbstractItemModel interface ===========================
public:
int rowCount(const QModelIndex &parent) const;
QVariant data(const QModelIndex &index, int role) const;
// ========================================================

private:
QList<PixmapPair*> _data;
};

#endif // IMAGELISTMODEL_H

///////////////////////
// imagelistmodel.cpp /
#include "imagelistmodel.h"

ImageListModel::ImageListModel(std::initializer_list<QString> files, QObject *parent)
: QAbstractListModel(parent)
{
auto iter = files.begin();

while (iter != files.end())
{
QPixmap large(*iter);
PixmapPair *pair = new PixmapPair();
pair->_file = *iter;
pair->_large = large;
pair->_small = large.scaled(100, 100, Qt::KeepAspectRatio, Qt::SmoothTransformation);

_data.append(pair);
++iter;
}
}

ImageListModel::~ImageListModel()
{
qDeleteAll(_data);
}


int ImageListModel::rowCount(const QModelIndex &parent) const
{
// This function should return the number of rows contained in the parent
// parameter, the parent parameter is used for trees in order to retrieve the
// number of rows contained in each node. Since we are doing a list each element
// doesn't have child nodes so we return 0
// By convention an invalid parent means the topmost level of a tree. In our case
// we return the number of elements contained in our data store.
if (parent.isValid())
return 0;
else
return _data.count();
}

QVariant ImageListModel::data(const QModelIndex &index, int role) const
{
if (index.isValid())
{
switch (role)
{
case Qt::DecorationRole:
{
// DecorationRole = Icon show for a list
return _data.value(index.row())->_small;
}
case Qt::DisplayRole:
{
// DisplayRole = Displayed text
return _data.value(index.row())->_file;
}
case LargePixmapRole:
{
// This is a custom role, it will help us getting the pixmap more
// easily later.
return _data.value(index.row())->_large;
}
}
}

// returning a default constructed QVariant, will let Views knows we have nothing
// to do and we let the default behavior of the view do work for us.
return QVariant();
}
///////////////////////

我们的 list 现已准备就绪,我们几乎完成了。

// main.cpp ///////////
#include <QApplication>

#include <QSplitter>
#include <QLabel>
#include <QListView>

#include "imagelistmodel.h"

int main(int argc, char *argv[])
{
QApplication a(argc, argv);

QSplitter page;
QListView *imageList = new QListView(&page);
imageList->setModel(new ImageListModel({ "ocean.jpg", "forest.jpg" }, imageList));
// We tell the list view to show our icon, this mode will call the data function
// of our model with the role : DecorationRole.
imageList->setViewMode(QListView::IconMode);
// We want our list to show data vertically
imageList->setFlow(QListView::TopToBottom);
// We allow only one selection at a time in the list
imageList->setSelectionMode(QListView::SingleSelection);
QLabel *imagePresenter = new QLabel(&page);

// We connect to the signal emitted when the selection is changed
// to update the image presenter.
QObject::connect(imageList->selectionModel(), &QItemSelectionModel::selectionChanged, [imageList, imagePresenter] {
QModelIndex selectedIndex = imageList->selectionModel()->selectedIndexes().first();
// We use our custom role here to retrieve the large image using the selected
// index.
imagePresenter->setPixmap(selectedIndex.data(ImageListModel::LargePixmapRole).value<QPixmap>());
});

page.setWindowTitle("Images");
page.show();
return a.exec();
}

此解决方案的优点是:
- 我们可以通过将自定义 ListModel 包装到 QSortFilterProxyModel 中来轻松添加过滤。
- 无需创建和管理大量按钮。
- 模型永远不需要知道是谁在屏幕上显示它。
- 如果需要,QListView 将自动滚动。
- 使用自定义角色可以让我们轻松检索大图像。如果我们在另一列中添加大图像,它将显示在将此模型与 QTableView 一起使用时,当我们想从选定的索引中检索它时,我们必须创建一个指向正确列的新索引。 (并不难,但需要更多代码,如果我们将模型包装在 ProxyModel 中,则容易出错)

Lambda 解释

对于 C++ 中的 lambda,完整的语法是:

[CAPTURES]\(PARAMETERS\)->RESULT {FUNCTION}.  
  • 在方括号之间,我们捕获变量以便能够在 FUNCTION 中使用它们,而不必将它们作为参数传递。
  • 圆括号之间的 PARAMETERS 与任何其他函数具有相同的含义,如果省略,则 lambda 不采用任何参数。
  • RESULT 是 FUNCTION 的返回类型,可以省略。
  • FUNCTION body 执行

在这个例子中,我决定忽略信号给出的参数,所以我省略了括号。我使用捕获的控件来检索用户选择并更新显示的图片。

关于c++ - Qt中的图像浏览器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24623130/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com