Forward QML property binding in C++
-
wrote on 4 Feb 2021, 15:48 last edited by Asperamanca 2 Apr 2021, 15:49
I'd like to write a C++ adapter class that can be used in QML like this:
Image { id: closeImage source: resource.svg(":/icons/close", closeImage.width, closeImage.height).Url }
"resource" is a QObject with a Q_INVOKABLE function named "svg".
The function accepts a resource path (QString) and a desired width and height.Q_INVOKABLE QVariant svg(const QString& resourcePath, const QVariant& width, const QVariant& height);
It returns an intermediate QObject, which has a Property called "Url" with getter and notifier signal.
class SvgResourceEntry : public QObject { Q_OBJECT QML_ANONYMOUS Q_PROPERTY(QUrl Url READ getUrl NOTIFY notifyUrlChanged) //...
Now, if the width and height (parameters 2 and 3) change, I'd like the C++ adapter to know. In this case, I would generate a new image of the correct size, and change the returned Url (probably asynchronously with time delay, but still). Through property binding, the Image component would load the changed image.
For this to work, I not only need the current width and height values, but actually the properties, so I can connect to the respective change signals.
Problem is, if I pass closeImage.width and height like seen above, on the C++ side I only see a double value (QVariant-type 6), not a QQmlProperty object or something like it.
So how could I achieve this property binding into C++?
-
wrote on 4 Feb 2021, 17:22 last edited by
@Asperamanca said in Forward QML property binding in C++:
source: resource.svg(":/icons/close", closeImage.width, closeImage.height).Url
source: resource.svg(":/icons/close", closeImage.width, closeImage.height).Url
This would get reevaluated when the width or height changes. Just make sure the Url that it produces is slightly different each time. That way closeImage will update itself. I don't know the details of your SvgResourceEntry. What does the Url return? Is this a generated resource? Can you change the name.
Another possibility is to blank out the Url. Then do a call later in the C++ code to update the Url. This should trigger Image to re-fetch the image.
-
@Asperamanca said in Forward QML property binding in C++:
source: resource.svg(":/icons/close", closeImage.width, closeImage.height).Url
source: resource.svg(":/icons/close", closeImage.width, closeImage.height).Url
This would get reevaluated when the width or height changes. Just make sure the Url that it produces is slightly different each time. That way closeImage will update itself. I don't know the details of your SvgResourceEntry. What does the Url return? Is this a generated resource? Can you change the name.
Another possibility is to blank out the Url. Then do a call later in the C++ code to update the Url. This should trigger Image to re-fetch the image.
wrote on 5 Feb 2021, 07:27 last edited by@fcarney said in Forward QML property binding in C++:
source: resource.svg(":/icons/close", closeImage.width, closeImage.height).Url
This would get reevaluated when the width or height changes.
Really? Even if resource.svg is a Q_INVOKABLE, and not a property? That has serious performance implications in other use cases...
What does the Url return? Is this a generated resource? Can you change the name.
I intend to use QQuickImageProvider, so I can return what I want.
Sounds like an approach worth to try. Thanks!
-
wrote on 5 Feb 2021, 15:03 last edited by fcarney 2 May 2021, 15:04
@Asperamanca said in Forward QML property binding in C++:
Really? Even if resource.svg is a Q_INVOKABLE, and not a property? That has serious performance implications in other use cases...
What performance implications? Any expression that has a value change can be reevaluated.
Now, if the width and height (parameters 2 and 3) change, I'd like the C++ adapter to know. In this case, I would generate a new image of the correct size, and change the returned Url
Isn't this reevaluation what you want to happen?
This is what will happen when the inputs change. You can test with a Q_INVOKABLE, but I would expect the same behavior.
property int countint: 0 property int changing: changeCall(countint) function changeCall(input){ console.log("changeCall", countint) return input+1 } onChangingChanged: console.log("changing", changing) Timer { interval: 1000 running: true repeat: true onTriggered: { countint = countint + 1 } }
-
wrote on 9 Feb 2021, 09:57 last edited by
Yes, it does make sense, when I think a little about it. And if you know that is how it works, it can actually simplify some code.
Thanks!
1/5