如何 通过QGalleryQueryModel 制作一个简单的图片浏览器
(Liuting - - →代码实现) |
(Renlin -) |
||
| (6 intermediate revisions by 2 users not shown) | |||
| Line 1: | Line 1: | ||
| − | [[Category: | + | [[Category:Qt]][[Category:Qt Mobility]][[Category:Imaging]][[Category:Symbian]][[Category:MeeGo Harmattan]][[Category:Lang-Chinese]] |
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | ||
{{ArticleMetaData <!-- v1.2 --> | {{ArticleMetaData <!-- v1.2 --> | ||
| − | |sourcecode= | + | |sourcecode= [[Media:Mediabrowser.zip]] |
|installfile= <!-- Link to installation file (e.g. [[Media:The Installation File.sis]]) --> | |installfile= <!-- Link to installation file (e.g. [[Media:The Installation File.sis]]) --> | ||
|devices= <!-- Devices tested against - e.g. ''devices=Nokia 6131 NFC, Nokia C7-00'') --> | |devices= <!-- Devices tested against - e.g. ''devices=Nokia 6131 NFC, Nokia C7-00'') --> | ||
| Line 12: | Line 7: | ||
|platform= <!-- Compatible platforms - e.g. Symbian^1 and later, Qt 4.6 and later --> | |platform= <!-- Compatible platforms - e.g. Symbian^1 and later, Qt 4.6 and later --> | ||
|devicecompatability= <!-- Compatible devices e.g.: All* (must have internal GPS) --> | |devicecompatability= <!-- Compatible devices e.g.: All* (must have internal GPS) --> | ||
| − | |dependencies= <!-- Any other/external dependencies e.g.: Google Maps Api v1.0 --> | + | |dependencies= <!-- Any other/external dependencies e.g.: Google Maps Api v1.0 --> |
| − | |signing=<!-- Signing requirements - empty or one of: Self-Signed, DevCert, Manufacturer --> | + | |signing= <!-- Signing requirements - empty or one of: Self-Signed, DevCert, Manufacturer --> |
|capabilities= <!-- Capabilities required by the article/code example (e.g. Location, NetworkServices. --> | |capabilities= <!-- Capabilities required by the article/code example (e.g. Location, NetworkServices. --> | ||
|keywords= <!-- APIs, classes and methods (e.g. QSystemScreenSaver, QList, CBase --> | |keywords= <!-- APIs, classes and methods (e.g. QSystemScreenSaver, QList, CBase --> | ||
| − | |language= | + | |language= Lang-Chinese |
|translated-by= <!-- [[User:XXXX]] --> | |translated-by= <!-- [[User:XXXX]] --> | ||
| − | |translated-from-title= <!-- Title only --> | + | |translated-from-title= <!-- Title only --> |
|translated-from-id= <!-- Id of translated revision --> | |translated-from-id= <!-- Id of translated revision --> | ||
| − | |review-by=<!-- After re-review: [[User:username]] --> | + | |review-by= <!-- After re-review: [[User:username]] --> |
|review-timestamp= <!-- After re-review: YYYYMMDD --> | |review-timestamp= <!-- After re-review: YYYYMMDD --> | ||
|update-by= <!-- After significant update: [[User:username]]--> | |update-by= <!-- After significant update: [[User:username]]--> | ||
|update-timestamp= <!-- After significant update: YYYYMMDD --> | |update-timestamp= <!-- After significant update: YYYYMMDD --> | ||
| − | |creationdate= | + | |creationdate= 20120328 |
| − | |author= | + | |author= [[User:Liuting]] |
}} | }} | ||
| Line 32: | Line 27: | ||
== 代码实现 == | == 代码实现 == | ||
| − | + | ===ThumbnailModel.h=== | |
<code> | <code> | ||
class ThumbnailModel : public QGalleryQueryModel | class ThumbnailModel : public QGalleryQueryModel | ||
| Line 55: | Line 50: | ||
}; | }; | ||
| − | < | + | <code> |
首先我们必须从 QGalleryQueryModel 派生一个类,并且重写data()方法 | 首先我们必须从 QGalleryQueryModel 派生一个类,并且重写data()方法 | ||
| − | + | ===ThumbnailModel.cpp=== | |
<code> | <code> | ||
QVariant ThumbnailModel::data(const QModelIndex &index, int role) const | QVariant ThumbnailModel::data(const QModelIndex &index, int role) const | ||
| Line 74: | Line 69: | ||
</code> | </code> | ||
| − | 在data 函数中我们返回已经缩放好的图片, | + | 在data 函数中我们返回已经缩放好的图片, 以便VIEW绘制。在thumbnailLoaded()函数中我们需要发送一个信号通知VIEW MODEL中的数据有所更新,以便VIEW进行更新。 |
| + | ===thumbnailcache.h=== | ||
| + | <code> | ||
| + | class ThumbnailCache : public QThread | ||
| + | { | ||
| + | Q_OBJECT | ||
| + | public: | ||
| + | ThumbnailCache(QObject *parent = 0); | ||
| + | ~ThumbnailCache(); | ||
| + | |||
| + | QString thumbnail(const QUrl &url); | ||
| + | |||
| + | bool event(QEvent *event); | ||
| + | |||
| + | signals: | ||
| + | void thumbnailReady(); | ||
| + | |||
| + | protected: | ||
| + | void run(); | ||
| + | |||
| + | private: | ||
| + | QImage loadImage(const QUrl &url) const; | ||
| + | QString thumbnailPath(const QUrl &url) const; | ||
| + | |||
| + | QMutex mutex; | ||
| + | QWaitCondition waitCondition; | ||
| + | QCache<QUrl, Thumbnail> cache; | ||
| + | QQueue<QUrl> pendingUrls; | ||
| + | bool cancelled; | ||
| + | }; | ||
| + | </code> | ||
| + | 我们需要定义一个线程类,在run函数中实现图片的缩放 | ||
| + | ===thumbnailcache.cpp=== | ||
| + | <code> | ||
| + | QImage ThumbnailCache::loadImage(const QUrl &url) const | ||
| + | { | ||
| + | const QString fileName = thumbnailPath(url); | ||
| + | |||
| + | QImageReader reader(fileName); | ||
| + | reader.setQuality(25); | ||
| + | |||
| + | if (reader.supportsOption(QImageIOHandler::Size)) { | ||
| + | QSize size = reader.size(); | ||
| + | |||
| + | if (!reader.supportsOption(QImageIOHandler::ScaledSize) | ||
| + | && (size.width() > 1280 || size.height() > 1280)) { | ||
| + | return QImage(); | ||
| + | } | ||
| + | |||
| + | if (size.width() > ThumbnailModel::thumbnailSize.width() | ||
| + | || size.height() > ThumbnailModel::thumbnailSize.height()) { | ||
| + | size.scale(ThumbnailModel::thumbnailSize, Qt::KeepAspectRatio); | ||
| + | } | ||
| + | |||
| + | reader.setScaledSize(size); | ||
| + | } else { | ||
| + | reader.setScaledSize(ThumbnailModel::thumbnailSize); | ||
| + | } | ||
| + | |||
| + | return reader.read(); | ||
| + | } | ||
| + | </code> | ||
| + | 我们将在loadImage()函数中通过QImageReader 对图片进行快速缩放 | ||
| + | ===photodelegate.h=== | ||
| + | <code> | ||
| + | #ifndef PHOTODELEGATE_H | ||
| + | #define PHOTODELEGATE_H | ||
| + | |||
| + | #include <QtGui/QAbstractItemDelegate> | ||
| + | #include <qDebug> | ||
| + | class PhotoDelegate : public QAbstractItemDelegate | ||
| + | { | ||
| + | Q_OBJECT | ||
| + | public: | ||
| + | PhotoDelegate(QObject *parent = 0); | ||
| + | ~PhotoDelegate(); | ||
| + | |||
| + | void paint( | ||
| + | QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; | ||
| + | |||
| + | QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const; | ||
| + | }; | ||
| + | |||
| + | #endif | ||
| + | </code> | ||
| + | 我们将定义一个类派生自 QAbstractItemDelegate,用于进行图片的绘制 | ||
| + | |||
| + | ===photodelegate.cpp=== | ||
| + | <code> | ||
| + | void PhotoDelegate::paint( | ||
| + | QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const | ||
| + | { | ||
| + | qDebug()<<"enter paint"; | ||
| + | |||
| + | QPen oldPen = painter->pen(); | ||
| + | |||
| + | QStyle *style = QApplication::style(); | ||
| + | |||
| + | int margin = style->pixelMetric(QStyle::PM_ButtonMargin); | ||
| + | |||
| + | QRect rect = option.rect; | ||
| + | |||
| + | if (option.state & QStyle::State_HasFocus) { | ||
| + | painter->fillRect(rect, option.palette.highlight()); | ||
| + | |||
| + | painter->setPen(option.palette.color(QPalette::HighlightedText)); | ||
| + | } | ||
| + | |||
| + | rect.adjust(margin, margin, -margin, -margin); | ||
| + | |||
| + | QRect decorationRect = rect; | ||
| + | decorationRect.setRight(decorationRect.left() + option.decorationSize.width()); | ||
| + | |||
| + | QPixmap decoration = qvariant_cast<QPixmap>(index.data(Qt::DecorationRole)); | ||
| + | if (!decoration.isNull()) | ||
| + | style->drawItemPixmap(painter, decorationRect, Qt::AlignCenter, decoration); | ||
| + | else | ||
| + | painter->drawRect(decorationRect); | ||
| + | |||
| + | painter->setPen(oldPen); | ||
| + | } | ||
| + | |||
| + | QSize PhotoDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &) const | ||
| + | { | ||
| + | int margin = QApplication::style()->pixelMetric(QStyle::PM_ButtonMargin); | ||
| + | |||
| + | QSize size = option.decorationSize; | ||
| + | |||
| + | size.rheight() += 2 * margin; | ||
| + | size.rwidth() += 2 * margin; | ||
| + | |||
| + | return size; | ||
| + | } | ||
| + | </code> | ||
| + | 我们在Paint()函数中绘制从MODEL中获得的数据,这样我们就完成了一个简单图片浏览器 | ||
== 代码下载== | == 代码下载== | ||
| + | [[file:Mediabrowser.zip]] | ||
| + | |||
== 相关链接 == | == 相关链接 == | ||
''Add categories below. Remove Category:Draft when the page is complete or near complete'' | ''Add categories below. Remove Category:Draft when the page is complete or near complete'' | ||
| + | [[Category:Code Examples]] | ||
Latest revision as of 06:18, 11 July 2012
文章信息
Contents |
介绍
QML 提供了一个 plugin DocumentGalleryMode ,通过使用这个plugin,我们可以很简单的实现一个图片浏览器,但是随着图片的增加,我们会发现加载速度十分缓慢,用户体验很差,这是由于QML 内部实现采取高质量的平滑缩放耗时很长,所以我们不的不重新实现自己的model ,并在线程中通过QImageReader 实现大量图片的快速缩放。接下来我们通过代码片段来看下具体的实现过程
代码实现
ThumbnailModel.h
class ThumbnailModel : public QGalleryQueryModel
{
Q_OBJECT
public:
static const QSize thumbnailSize;
ThumbnailModel(QAbstractGallery *gallery, QObject *parent = 0);
~ThumbnailModel();
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
protected:
virtual QUrl imageUrl(const QModelIndex &index) const;
private slots:
void thumbnailLoaded();
private:
mutable ThumbnailCache cache;
};
<code>
首先我们必须从 QGalleryQueryModel 派生一个类,并且重写data()方法
===ThumbnailModel.cpp===
<code>
QVariant ThumbnailModel::data(const QModelIndex &index, int role) const
{
qDebug()<<"enter data";
return role == Qt::DecorationRole && index.isValid()
? cache.thumbnail(imageUrl(index))
: QGalleryQueryModel::data(index, role);
}
void ThumbnailModel::thumbnailLoaded()
{
emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() -1));
}
在data 函数中我们返回已经缩放好的图片, 以便VIEW绘制。在thumbnailLoaded()函数中我们需要发送一个信号通知VIEW MODEL中的数据有所更新,以便VIEW进行更新。
thumbnailcache.h
class ThumbnailCache : public QThread
{
Q_OBJECT
public:
ThumbnailCache(QObject *parent = 0);
~ThumbnailCache();
QString thumbnail(const QUrl &url);
bool event(QEvent *event);
signals:
void thumbnailReady();
protected:
void run();
private:
QImage loadImage(const QUrl &url) const;
QString thumbnailPath(const QUrl &url) const;
QMutex mutex;
QWaitCondition waitCondition;
QCache<QUrl, Thumbnail> cache;
QQueue<QUrl> pendingUrls;
bool cancelled;
};
我们需要定义一个线程类,在run函数中实现图片的缩放
thumbnailcache.cpp
QImage ThumbnailCache::loadImage(const QUrl &url) const
{
const QString fileName = thumbnailPath(url);
QImageReader reader(fileName);
reader.setQuality(25);
if (reader.supportsOption(QImageIOHandler::Size)) {
QSize size = reader.size();
if (!reader.supportsOption(QImageIOHandler::ScaledSize)
&& (size.width() > 1280 || size.height() > 1280)) {
return QImage();
}
if (size.width() > ThumbnailModel::thumbnailSize.width()
|| size.height() > ThumbnailModel::thumbnailSize.height()) {
size.scale(ThumbnailModel::thumbnailSize, Qt::KeepAspectRatio);
}
reader.setScaledSize(size);
} else {
reader.setScaledSize(ThumbnailModel::thumbnailSize);
}
return reader.read();
}
我们将在loadImage()函数中通过QImageReader 对图片进行快速缩放
photodelegate.h
#ifndef PHOTODELEGATE_H
#define PHOTODELEGATE_H
#include <QtGui/QAbstractItemDelegate>
#include <qDebug>
class PhotoDelegate : public QAbstractItemDelegate
{
Q_OBJECT
public:
PhotoDelegate(QObject *parent = 0);
~PhotoDelegate();
void paint(
QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
};
#endif
我们将定义一个类派生自 QAbstractItemDelegate,用于进行图片的绘制
photodelegate.cpp
void PhotoDelegate::paint(
QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
qDebug()<<"enter paint";
QPen oldPen = painter->pen();
QStyle *style = QApplication::style();
int margin = style->pixelMetric(QStyle::PM_ButtonMargin);
QRect rect = option.rect;
if (option.state & QStyle::State_HasFocus) {
painter->fillRect(rect, option.palette.highlight());
painter->setPen(option.palette.color(QPalette::HighlightedText));
}
rect.adjust(margin, margin, -margin, -margin);
QRect decorationRect = rect;
decorationRect.setRight(decorationRect.left() + option.decorationSize.width());
QPixmap decoration = qvariant_cast<QPixmap>(index.data(Qt::DecorationRole));
if (!decoration.isNull())
style->drawItemPixmap(painter, decorationRect, Qt::AlignCenter, decoration);
else
painter->drawRect(decorationRect);
painter->setPen(oldPen);
}
QSize PhotoDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &) const
{
int margin = QApplication::style()->pixelMetric(QStyle::PM_ButtonMargin);
QSize size = option.decorationSize;
size.rheight() += 2 * margin;
size.rwidth() += 2 * margin;
return size;
}
我们在Paint()函数中绘制从MODEL中获得的数据,这样我们就完成了一个简单图片浏览器
代码下载
相关链接
Add categories below. Remove Category:Draft when the page is complete or near complete

