Qt/QML : Send QImage From C++ to QML and Display The QImage On GUI
c++, qml, qt
Solution
In other words, you have a class emitting a signal carrying a QImage and want to update an item in QML with that image? There are various solutions, none of which involves "converting a QImage to a QUrl" (whatever that means, surely you don't need to get a `data` URL carrying your image data...)
Use an image provider
This means you can use a plain `Image` item in your QML files.
- Create a `QQuickImageProvider` subclass; give it a `QImage` member (the image to provider), override `requestImage` to provide that image (the actual `id` requested does not really matter, see below), and a slot that receives a `QImage` and updates the member.
- Connect your `Publisher` signal to your provider's slot
- Install the provider into the QML engine via `QQmlEngine::addImageProvider` (see `QQuickView::engine`); again the `id` does not really matter, just use a sensible one
In QML, just use a plain `Image` element with a source like this
Image {
id: myImage
source: "image://providerIdPassedToAddImageProvider/foobar"
}
`foobar` will be passed to your provider, but again, it doesn't really matter.
We're almost there, we now only need a way to push the image updates to the QML world (otherwise Image will never know when to update itself). See my answer here for how to do that with a `Connections` element and a bit of JS.
Note that in general you don't need to make `Publisher` a QML type, you just need to create one instance in C++ and expose it to the QML world via `QQmlContext::setContextProperty`.
Use a custom Qt Quick 2 Item
`QQuickPaintedItem` is probably the most convenient for the job as it offers a `paint` method taking a `QPainter`. Hence the big plan is
- Subclass `QQuickPaintedItem`: the subclass stores the `QImage` to be painted and has a slot that sets the new QImage. Also its `paint` implementation simply paints the image using `QPainter::drawImage`.
- Expose the subclass to the QML world via `qmlRegisterType` (so that you can use it in QML)
Figure out a way to connect the signal carrying the new image to the items' slot.
This might be the tricky part.
To perform the connection in C++ you need a way to figure out that the item has been created (and get a pointer to it); usually one does this by means of assigning the `objectName` property to some value, then using `findChild` on the root object (as returned by `QQuickView::rootObject()`) to get a pointer to the item itself. Then you can use `connect` as usual.
Or, could instead perform the connection in QML, just like above, via a `Connections` element on the publisher C++ object exposed to the QML world:
MyItem {
id: myItem
}
Connections {
target: thePublisherObjectExposedFromC++
onNewImage: myItem.setImage(image)
}
This has the advantage of working no matter when you create the MyItem instance; but I'm not 100% sure it will work because I'm not sure you can handle the `QImage` type in QML.
Problem
I created a class `Publisher` which periodically emits a `QImage` object. However I'm having a tough time drawing the `QImage` to a QML element. It appears that the `Image` and `Canvas` QML components require a `QUrl` instead of a `QImage`, but I'm not sure how to convert my `QImage` to a `QUrl`. Edit4: When I say QUrl, I don't mean I'm trying to convert an image to a URL. That's nonsense. I mean I want to generate a reference to this image, which is not on disk, and the data type that QML components are asking for is a URL. I've done some research and found that `QQuickImageProvider` provides a solution, but I haven't found any documentation explaining how to convert my `QImage` signal to a `QUrl` that I can use for drawing. Any example code or reference documentation would be appreciated. Thanks for your help! Edit1: I've taken a look here: http://qt-project.org/doc/qt-5.0/qtquick/qquickimageprovider.html and I do not see how I pass a QImage to the quick image provider and from it create a QUrl. Edit2. Here is the header. The implementation should not be important. ``` class Publisher { Q_OBJECT public: Publisher(QObject* parent = 0); virtual ~Publisher(void); Q_SIGNALS: void newImage(const QImage& newImage); }; ``` Edit 3. Here is my QML code, but I don't know how to draw my QImage, so this code is kind of meaningless. my main.cpp file: ``` int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); qmlRegisterType<Publisher>("Components", 1, 0, "Publisher"); QtQuick2ApplicationViewer viewer; viewer.setMainQmlFile(QStringLiteral("qml/QQuickViewExample/main.qml")); viewer.showExpanded(); return app.exec(); } ``` my main.qml file: ``` import QtQuick 2.0 import Components 1.0 Rectangle { id : testRect width: 360 height: 360 Image{ anchors.fill: parent id: myImage Publisher { id: myPub onNewImage: { myImage.source = newImage; #I know this doesnt work, it needs a QUrl and not a QImage } } } } ```