QQuickImageProvider的正确使用方法是什么?

6
我需要动态选择qpixmap以在QML Image项中显示。这些qpixmap应该从源qpixmap裁剪,我将从QML文件中设置它们。我希望它们能够在第一次从QML进行动态图像处理时由C++代码进行裁剪并缓存以备将来使用。对于动态图像操作,应该从QQuickImageProvider派生出自己的类,并将其加载到QML应用程序引擎中。但是我如何控制源qpixmap呢?通过属性吗?如果是的话,那么我的自定义提供程序必须从QObject派生,并且它的实例应该在QML内声明,不是吗?但是它如何被引擎加载呢?我感觉这种实现方式是错误的,但哪种方式才是正确的呢?
更新:好的,我有一个类:
class MyQuickImageProvider : public QQuickImageProvider {
public:
    ...
    // This method should set the source image path
    void setPath ( QUrl path );
    // Overriden method of base class; should return cropped image
    virtual QPixmap requestPixmap ( const QString &id, QSize *size, const QSize &requestedSize );
    ...
}

在 main.cpp 中,它被加载为:

QQmlApplicationEngine engine;
...
engine.addImageProvider("my_quick_image_provider", new MyQuickImageProvider(QQmlImageProviderBase::Image));

我想通过QML更改源图像路径。如何使setPath方法可以被访问?显而易见的方法是将该方法声明为Q_INVOKABLE(并从QObject派生MyQuickImageProvider并进行qmlRegisterType),但此时我应该在QML源中声明我的类的实例:

MyQuickImageProvider {
    id: my_quick_image_provider
    ...
}

从main.cpp访问它将会有问题。而且这样的设计对我来说似乎很奇怪。有没有更优雅的解决方案?


这个问题对我来说相当令人困惑。你遇到的实际问题是什么?你的代码是什么样子的? - Mitch
2个回答

6

您不会将MyQuickImageProvider用作QML对象,也不会定义Q_INVOKABLE方法,因为您无法从QML访问图像提供程序对象。

engine.addImageProvider("my_quick_image_provider", [...]

设置了访问图像的名称,例如:

// qml file
Image {
    source: "image://my_quick_image_provider/name_of_my_image"
}

后面的部分“name_of_my_image”被称为id,你可以在中找到它。
virtual QPixmap requestPixmap ( const QString &id, QSize *size, const QSize &requestedSize );

现在在你的 MyQuickImageProvider 类中实现 requestPixmap 方法,并使用 id 字符串生成 QPixmap。
我认为可以丢弃 void setPath ( QUrl path ); 方法,因为你只需要一个图像提供者实例来处理所有这种类型的图像。
由于构造函数不会从基类继承,所以我认为 new MyQuickImageProvider(QQmlImageProviderBase::Image) 没有意义。最好添加一个没有参数的构造函数。
class MyQuickImageProvider : public QQuickImageProvider {
public:
    MyQuickImageProvider();
    // ...

并在您的初始化程序列表中设置图像类型:

MyQuickImageProvider::MyQuickImageProvider()
    : QQuickImageProvider(QQuickImageProvider::Pixmap)
{
}

谢谢你的回答,Simon!据我理解,这个算法将需要在每次请求 requestPixmap 时检查源图像是否发生了变化(而 setPath 则可以避免每次都进行检查)。这个过程能否进行优化? - Vercetti
QML会为给定的image:// url缓存Image的像素图,因此假设底层图像不经常更改。您从哪里获取这些图像?如果您已经有一种通知您图像何时更改的方法,请使用信号/槽将该信息传递给图像提供程序。但是,只要您掌握了基础知识,就应将其放入后续问题中。 - Simon Warta
我已经从文件中加载了源图像(“big”),并且有小图像的qhash;每个小图像都是从大图像中“懒惰地”裁剪出来并放入qhash中,当第一次请求其ID时。因此,我需要频繁更改小图像,而大图像则要少得多。现在,我将通过属性控制大图像文件名。 - Vercetti

0

在Qt-6.2.4中创建和测试

main.cpp - 默认Qt代码,除了engine.addImageProvider("colors", new test);这一行

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "test.h"
int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;

    engine.addImageProvider("colors", new test);

    const QUrl url(u"qrc:/qimgprovider/main.qml"_qs);
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);
    return app.exec();
}

test.cpp

#include "test.h"

test::test() : QQuickImageProvider(QQuickImageProvider::Pixmap)
{ 
}
    
QPixmap test::requestPixmap(const QString &id, QSize *size, const QSize &requestedSize)
{
   int width = 100;
   int height = 50;
   if (size)
      *size = QSize(width, height);
   QPixmap pixmap(requestedSize.width() > 0 ? requestedSize.width() : width,
                  requestedSize.height() > 0 ? requestedSize.height() : height);
   pixmap.fill(QColor(id).rgba());
   return pixmap;
}

test.h

#ifndef TEST_H
#define TEST_H

#include <QQuickImageProvider>

class test : public QQuickImageProvider
{
public:
    test();
    QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) override;
};

#endif // TEST_H

main.qml

import QtQuick

Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("Glory to Ukraine!")
    Column {
        Image { source: "image://colors/blue" }
        Image { source: "image://colors/yellow" }
    }
}

qimgprovider 是 Qt 项目的名称。 - Mykola M.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接