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 } } } }
A signal is automatically emitted when the value of a QML property changes. This type of signal is a property change signal and signal handlers for these signals are written in the form on<Property>Changed, where <Property> is the name of the property, with the first letter capitalized.
Connecting to QML Signals All QML signals are automatically available to C++, and can be connected to using QObject::connect() like any ordinary Qt C++ signal. In return, any C++ signal can be received by a QML object using signal handlers.
QML (Qt Modeling Language) is a user interface markup language. It is a declarative language (similar to CSS and JSON) for designing user interface–centric applications. Inline JavaScript code handles imperative aspects.
With the QML type compiler, you will be able to compile your object structure to C++. Each QML component becomes a C++ class this way.
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...)
This means you can use a plain Image item in your QML files.
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.Publisher signal to your provider's slot QQmlEngine::addImageProvider (see QQuickView::engine); again the id does not really matter, just use a sensible oneIn 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.
QQuickPaintedItem is probably the most convenient for the job as it offers a paint method taking a QPainter. Hence the big plan is
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.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.
When I've had image-producing C++ classes I've wanted to embed in QML, I've always done it by making the C++ class a subclass of QDeclarativeItem (there'll be a new QtQuick 2.0 equivalent of course), overriding the paint method with the appropriate drawing code, which maybe as simple as
void MyItem::paint(QPainter* painter,const QStyleOptionGraphicsItem*,QWidget*) { painter->drawImage(QPointF(0.0f,0.0f),_image); } if you have a QImage of the right size already... and Job Done. For animation, just ping update() when there's something new to draw.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With