I have a imageprovider object based in QQuickImageProvider class that with a requestImage function generates a QR image that is created with a qrencode library. That Image painted is showed in a qml page that I show in a display. The code works well and paints the QR Image successfully whith the default string, but I want to update or refresh the QR image everytime I receive a new string to encript and show in display.

QQuickImageProvider doesn't have a public function to connect from another object, or maybe I don't know if exists.

There is a way to update the image everytime I receive a new data event?

There is a similar question in Example but I can't understand the way is resolved.

Here is the code I use:

imageprovider.h

#ifndef IMAGE_PROVIDER_H
#define IMAGE_PROVIDER_H

#include <QQuickImageProvider>
#include <QPixmap>
#include <QPainter>

class ImageProvider : public QQuickImageProvider
{

public:
    ImageProvider();
    QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize);
    void loadData(QString newdata);

private:
    QString data;
};
#endif // IMAGE_PROVIDER_H

imageprovider.cpp

#include "imageprovider.h"
#include <QPainter>
#include <qrencode.h>


ImageProvider::ImageProvider() : QQuickImageProvider(QQuickImageProvider::Image) {

}

QImage ImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize) {
    int width = 120;
    int height = 120;
    QImage img(requestedSize.width() > 0 ? requestedSize.width() : width,
               requestedSize.height() > 0 ? requestedSize.height() : height,
               QImage::Format_RGB32);
    //QRcode *qr = QRcode_encodeString("HELLO WORLD", 1, QR_ECLEVEL_L, QR_MODE_8, 1);
    QRcode *qr = QRcode_encodeString(data.toStdString().c_str(), 1, QR_ECLEVEL_L, QR_MODE_8, 1);
    if(0!=qr){
        QPainter painter(&img);
        QColor fg("black");
        QColor bg("white");
        painter.setBrush(bg);
        painter.setPen(Qt::NoPen);
        painter.drawRect(0,0,120,120);
        painter.setBrush(fg);
        const int s=qr->width>0?qr->width:1;
        const double w=120;
        const double h=120;
        const double aspect=w/h;
        const double scale=((aspect>1.0)?h:w)/s;
        for(int y=0;y<s;y++){
            const int yy=y*s;
            for(int x=0;x<s;x++){
                const int xx=yy+x;
                const unsigned char b=qr->data[xx];
                if(b &0x01){
                    const double rx1=x*scale, ry1=y*scale;
                    QRectF r(rx1, ry1, scale, scale);
                    painter.drawRects(&r,1);
                }
            }
        }
        QRcode_free(qr);
    }
    return img;
}

void ImageProvider::loadData(QString newdata)
{
    data = newdata;
}

main.cpp

QGuiApplication app(argc, argv);
...
ImageProvider ImageProvider;
engine.addImageProvider(QLatin1String("ImageProvider"), &ImageProvider);

QRImage.qml

import QtQuick 2.6
import QtQuick.Layouts 1.0
import QtQuick.Controls 2.1


Image {
    id: qr
    source: "image://ImageProvider/"
    sourceSize.width: 120
    sourceSize.height: 120
    cache: false
}
2

There are 2 best solutions below

0
Luca Carlon On

What I typically do in this case is to simply change the URL of the image provider including some random number, which is then ignored in the provider itelf. So change "image://ImageProvider/something" to "image://ImageProvider/somethingelse". I typically use a random number. This way, when the URL changes, the provider is queried again and your implementation of requestImage(...) is re-evaluated.

0
Alexander Dyagilev On

You can set source to an empty string and then set it back to the original URL. This will force the image to be refreshed.

function refreshImage()
{
    let source = qr.source;
    qr.source = "";
    qr.source = source;
}