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