Reputation: 457
I need to select dynamically qpixmaps to display inside QML Image items. That qpixmaps should be cropped from the source qpixmap, which I'm going to set from the QML file. I'd like them to be cropped by C++ code on the first demand from QML and to be cached for the future use. For dynamical images manipulating it's ought to derive my own class from QQuickImageProvider and load it to QML Application engine. But how can I control the source qpixmap then? Via property? If yes, then my custom provider must be derived from QObject and it's instance should be declared inside QML, isn't it? But how can it be loaded by the engine then? I feel that this way of implementing is wrong, but which one would be correct?
UPD: Ok, I have a class:
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 );
...
}
In main.cpp it's loaded as:
QQmlApplicationEngine engine;
...
engine.addImageProvider("my_quick_image_provider", new MyQuickImageProvider(QQmlImageProviderBase::Image));
I'd like to change source image path via QML. How can I make setPath method accessible to it? The obvious way is to declare the method as Q_INVOKABLE (and derive MyQuickImageProvider from QObject and qmlRegisterType it), but then I should declare the instance of my class within the QML source:
MyQuickImageProvider {
id: my_quick_image_provider
...
}
The access to it from main.cpp will be problematic. And such a design seems weird to me. Is there any more elegant solution?
Upvotes: 6
Views: 6440
Reputation: 21
Created and tested in Qt-6.2.4
main.cpp - with default Qt code except line 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" }
}
}
Upvotes: 1
Reputation: 11408
You do not use MyQuickImageProvider
as an QML object, nor do you define a Q_INVOKABLE
method because you cannot access the image provider object from QML.
engine.addImageProvider("my_quick_image_provider", [...]
sets the name how you access images, e.g.
// qml file
Image {
source: "image://my_quick_image_provider/name_of_my_image"
}
The later part "name_of_my_image" is called the id
, which you find in
virtual QPixmap requestPixmap ( const QString &id, QSize *size, const QSize &requestedSize );
Now implement requestPixmap
in your MyQuickImageProvider
and let it use the id
string to produce a QPixmap.
I think you can throw away the void setPath ( QUrl path );
method because you only need one image provider instance for all images of that kind.
Since constructors are not inherited from the base class, I don't think new MyQuickImageProvider(QQmlImageProviderBase::Image));
makes sense. Better add a constructor with no argument
class MyQuickImageProvider : public QQuickImageProvider {
public:
MyQuickImageProvider();
// ...
and have the image type in your initializer list:
MyQuickImageProvider::MyQuickImageProvider()
: QQuickImageProvider(QQuickImageProvider::Pixmap)
{
}
Upvotes: 6