I want to create a custom component, which allows two-way binding with the following (traditional) setup:
// main.qml
property var someStoredValue: someInitialValue // may be C++ property in real application
MyCustomComponent
{
myProperty: someStoredValue // this binding will be destroyed on user input
onMyPropertyChanged: someStoredValue = myProperty
}
// MyCustomComponent.qml
Item
{
property var myProperty: null
MouseArea
{
anchors.fill: parent
onClicked: myProperty = "some text or other value" // breaks the binding set in main.qml
}
}
MyCustomComponent
should be able to update myProperty
(programmatically), without destroying the binding between someStoredValue
and myProperty
. How can I change the implementation of MyCustomComponent
to achieve my goal?
One solution would be to use QObject::setProperty
to update the myProperty
without breaking the binding.
First, we should expose the QObject::setProperty
to QML, f.ex. using a singleton object:
#include <QObject>
class QmlHelper : public QObject
{
Q_OBJECT
public:
Q_INVOKABLE void setValue (QObject *pObject, const QString& name, QVariant v)
{
QByteArray n = name.toUtf8();
if (v.isNull())
v = QVariant(pObject->property(n.data()).userType(), nullptr); // ensure v is of correct type
pObject->setProperty(n.data(), v);
}
};
You should register the singleton type:
qmlRegisterSingletonType<QmlHelper>("MyUri", 1, 0, "QmlHelper", [](QQmlEngine *, QJSEngine *) -> QObject* {return new QmlHelper();});
MyCustomComponent
could now be implemented as:
Item
{
id: myComponent
property var myProperty: null
MouseArea
{
anchors.fill: parent
onClicked: QmlHelper.setValue(myComponent, "myProperty", "some text or other value"); // updates myProperty without breaking the binding
}
}
DISCLAIMER: Changing QML properties from C++ is a rather tricky solution and not well documented. Use at your own risk.