相关:QML Image 通过 QQuickAsyncImageProvider 异步加载图片-CSDN博客
QML 中使用 Image 来加载图片,有三种加载方式:
- 从 Qt 资源系统加载:qrc://图片路径
- 文件加载:file:///图片路径
- 由 ImageProvider 提供数据:image://provider路径
通过 ImageProvider,我们可以将内存中的图像由 QML Image 呈现。当然,如果单纯是想渲染内存中的图像数据,也可以直接用 QQuickItem 或者 QQuickPaintedItem 等。
继承 QQuickImageProvider,实现 request 相关接口返回图片或者纹理
class MyImageProvider : public QObject, public QQuickImageProvider
{
Q_OBJECT
public:
explicit MyImageProvider(QObject *parent = nullptr);
// 通过这个接口给qml Image提供数据
// 文档注释:此方法可能由多个线程调用,因此请确保此方法的实现是可重入的。
QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) override;
// 其他的接口
// QPixmap requestPixmap(const QString &id, QSize *size, const QSize& requestedSize) override;
// QQuickTextureFactory *requestTexture(const QString &id, QSize *size, const QSize &requestedSize) override;
};
qmlengine 调用 addImageProvider 注册一个该 Provider 对应的前缀
auto provider = new MyImageProvider(&app);
engine.rootContext()->setContextProperty("provider", provider);
// qml中就可以通过 "image://Provider/id" 的url来访问我们的接口
engine.addImageProvider("Provider", provider);
Image 通过 url 指定 Provider id 和 image id 获取数据
Image {
id: image
anchors.centerIn: parent
cache: false
// image://provider id/image id
source: "image://Provider/imageTag/0"
// 指定Image的sourceSize会作为requestedSize参数
// sourceSize: Qt.size(120, 120)
}
因为 Image 的 load 接口外部不能访问,只能修改 url 或者其他方式来重新加载图片数据,这对于加载图片文件也是一样的
updateNum++
image.source = "image://provider id/image id/" + updateNum
github 链接:https://github.com/gongjianbo/MyTestCode/tree/master/Qml/TestQml_20221225_ImageProvider
#pragma once
#include
#include
#include
#include
// 参考文档:https://doc.qt.io/qt-6/qquickimageprovider.html
class MyImageProvider : public QObject, public QQuickImageProvider
{
Q_OBJECT
public:
explicit MyImageProvider(QObject *parent = nullptr);
// 通过该接口给 QML Image 提供数据
// 文档注释:此方法可能由多个线程调用,因此请确保此方法的实现是可重入的
QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) override;
// 其他的接口
// QPixmap requestPixmap(const QString &id, QSize *size, const QSize& requestedSize) override;
// QQuickTextureFactory *requestTexture(const QString &id, QSize *size, const QSize &requestedSize) override;
signals:
// 测试刷新
void imageChanged(const QString &imageTag);
private:
// 测试定时刷新
QTimer *timer;
// 颜色
uchar gray{0};
// 表示内存中的图
QImage image;
};
#include "MyImageProvider.h"
MyImageProvider::MyImageProvider(QObject *parent)
: QObject{parent}
, QQuickImageProvider{QQuickImageProvider::Image}
, timer{new QTimer(this)}
{
// 生成一个 QImage 来测试
image = QImage(200, 200, QImage::Format_ARGB32);
image.fill(QColor(gray, gray, gray));
// 测试刷新
connect(timer, &QTimer::timeout, this, [this](){
gray++;
image.fill(QColor(gray, gray, gray));
emit imageChanged("imageTag");
});
timer->start(20);
}
QImage MyImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
{
// 指定 Image 的 sourceSize 会作为 requestedSize 参数,默认是 QSize(-1, -1)
Q_UNUSED(requestedSize)
// 若 url 为 "image://Provider/imageTag/0",那么 id 就是 "imageTag/0"
// 注意 url 的编码问题,如果有特殊符号之类的不能直接从中截取 QML 中设置的路径
if (id.startsWith("imageTag")) {
if (size) {
*size = image.size();
}
return image;
}
// 如果返回的 QImage 无效,QML 会报错,不过不需要报错,可以准备一个透明的 QImage
return QImage();
}
import QtQuick 2.15
import QtQuick.Window 2.15
Window {
width: 640
height: 480
visible: true
title: qsTr("Image Provider")
Image {
id: image
anchors.centerIn: parent
cache: false
// image://provider_id/image_id
source: "image://Provider/imageTag/0"
// 指定 Image 的 sourceSize 会作为 requestedSize 参数,默认是 QSize(-1, -1)
// sourceSize: Qt.size(120, 120)
}
property int updateNum: 0
Connections {
target: provider
function onImageChanged(imageTag) {
// Image 的 load 接口不是 public 的,所以只能切换 url 来重新加载数据
updateNum++
image.source = "image://Provider/" + imageTag + "/" + updateNum
}
}
}