[Solved] Send QImage from C++ to QML via QQuickImageProvider or using a signal



  • My C++ class receives signals that carry a QImage and I wish to update a corresponding QML image.

    The QQuickImageProvider seems unsuitable as it only allows the QML to pull the image across. So maybe I need to forward the signal to QML, but I'm not clear how to pass the image across. Is this documented anywhere please?

    Thanks.



  • One approach is to send signal to QML and then invoke na Image which will invoke your's QQuickImageProvider.

    Other is to implement your custom QML item implemented in C++ using scene graph API or maybe QQuickPaintedItem.



  • Hello,

    i also tried to pass an QImage to QML using a model. He receives the image and also detects it as a QImage but can't handle it, well at least the Image-component can't. You'll have to provide a source for it, that means using the QQuickImageProvider.

    Please see this thread for more informations: "Passing QImage to QML":http://qt-project.org/forums/viewthread/37485

    Answer from digia:

    bq. As Image requires url, you cannot directly specify QImage for it. One
    option would be to change the QImage to QString and then use the QString as image source. So add images to resource file and use in cpp:
    Constructor:
    @Animal(const QString &type, const QString &size, const QString &image);@
    Adding an animal:
    @model.addAnimal(Animal("Wolf", "Medium", "my_image.png")@
    and then in qml:
    @ListView {
    width: 200; height: 250

    model: myModel
    
    Component {
         id: modelDelegate
         Item {
             width: 180; height: 40
             Row {
                 Text { text: "Animal: " + type + ", " + size }
                 Image {source: image}
             }
         }
     }
    
    delegate: modelDelegate
    

    }@
    Another option would be to use QQuickImageProvider class.
    http://qt-project.org/doc/qt-5.0/qtquick/qquickimageprovider.html
    An example of how to use QQuickImageProvider can be found from:
    \qtdeclarative\examples\quick\imageprovider



  • Thanks for your suggestions guys. I had thought about a signal then a getImage via a provider, but wasn't clear how to refresh with a new image for the same id. That link suggested how to overcome that, but then I realized I needed a frame number as the id and everything would then work. And it does!

    The scene graph API is an interesting idea but a bit out of my comfort zone at the moment so that was my fallback which I didn't need in the end.

    This is what I ended up with, it seems quite neat and compact really. Good old Qt.

    main.cpp
    @#include <QtGui/QGuiApplication>
    #include <QQmlContext>
    #include <QTimer>
    #include "qtquick2applicationviewer.h"
    #include "NwImageProvider.h"

    int main(int argc, char *argv[])
    {
    QGuiApplication app(argc, argv);
    QTimer timer;
    NwImageProvider *imageProvider = new NwImageProvider;
    QtQuick2ApplicationViewer viewer;

    viewer.rootContext()->engine()->addImageProvider(QLatin1String("NwImageProvider"), imageProvider);
    viewer.rootContext()->setContextProperty("NwImageProvider", imageProvider);
    viewer.setMainQmlFile&#40;QStringLiteral("qml/ImageToQml/main.qml"&#41;);
    viewer.showExpanded();
    
    QObject::connect(&timer, SIGNAL(timeout()), imageProvider, SLOT(slotNewFrameReady()));
    timer.setInterval(1000);
    timer.setSingleShot(false);
    timer.start();
    
    return app.exec();
    

    }@

    main.qml
    @import QtQuick 2.1
    import QtQuick.Controls 1.0

    Rectangle {
    width: 360
    height: 360
    property bool isRedTop: false
    property int currentFrameNumber: 0

    Column {
        anchors.centerIn: parent
        Image { source: "image://NwImageProvider/" + currentFrameNumber}
        Image { source: "image://NwImageProvider/" + (currentFrameNumber + 1)}
    }
    
    Connections {
        target: NwImageProvider
        onSignalNewFrameReady: {
            console.log("onSignalNewFrameReady", frameNumber);
            currentFrameNumber = frameNumber;
        }
    }
    

    }
    @

    NwImageProvider.h
    @#include <QObject>
    #include <QQuickImageProvider>

    class NwImageProvider : public QObject, public QQuickImageProvider
    {
    Q_OBJECT
    public:
    NwImageProvider();
    QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize);

    public slots:
    void slotNewFrameReady();

    signals:
    Q_SIGNAL void signalNewFrameReady(int frameNumber);

    };
    @

    NwImageProvider.cpp
    @#include "NwImageProvider.h"

    NwImageProvider::NwImageProvider()
    : QQuickImageProvider(QQmlImageProviderBase::Image)
    {
    }

    QImage NwImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
    {
    int width = 100;
    int height = 50;
    int requestNumber;
    QString strId = id;
    bool bIsOk;

    this->blockSignals(true);   // To allow debugging
    
    requestNumber = strId.toInt(&bIsOk);
    if (bIsOk)
    {
        switch (requestNumber % 4)
        {
        case 0: strId = "yellow"; break;
        case 1: strId = "red"; break;
        case 2: strId = "green"; break;
        case 3: strId = "blue"; break;
        default: strId = "black"; break;
        }
    }
    if (size)
        *size = QSize(width, height);
    QImage image(requestedSize.width() > 0 ? requestedSize.width() : width,
                   requestedSize.height() > 0 ? requestedSize.height() : height, QImage::Format_RGB32);
    image.fill(QColor(strId).rgba());
    
    this->blockSignals(false);
    
    return image;
    

    }

    void NwImageProvider::slotNewFrameReady()
    {
    static int nextFrameNumber = 0;
    emit signalNewFrameReady(nextFrameNumber++);
    }
    @



  • great answer, I am looking for it.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.