QML Image 通过 QQuickImageProvider 加载图片

相关: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
        }
    }
}

你可能感兴趣的:(QML,三言两语,QML,Image)