Unsolved Dynamic Property Updates : It works, room for improvement/refinement?
-
I was looking into whether or not QObject dynamic properties could be auto updated in QML properties. I was looking for the possibility of dynamic properties in QML objects that could update when a dynamic property changes on a QObject. So I pieced together the following:
main.qml:import QtQuick 2.9 import QtQuick.Window 2.2 import QtQuick.Controls 2.5 Window { visible: true width: 640 height: 480 title: qsTr("Testing Dynamic Object Properties") property var plist: ({}) function createProperties(){ plist["one"] = 0 plist["two"] = "test" plist["three"] = 0.24 plist["four"] = 1 for(var key in plist) { dynamicObj.setProperty(key, plist[key]) } } function changeProperties(){ dynamicObj.setProperty("one",5) } Connections { target: dynamicObj onPropertyChanged: { console.log(name) plist[name] = dynamicObj.property(name) plistChanged() // causes entire structure to be reevaluated and all dependent properties to be updated } } Component.onCompleted: { console.log(dynamicObj.objectName) createProperties() //console.log("change things") //changeProperties() } Text{ id: text1 width: 50 height: 20 y:0 color: "black" text: plist["one"] } Text{ id: text2 width: 50 height: 20 y:20 color: "black" text: plist["two"] } Text{ id: text3 width: 50 height: 20 y:40 color: "black" text: plist["three"] } Text{ id: text4 width: 50 height: 20 y:60 color: "black" text: plist["four"] } Button { id: but_change anchors.top: text4.bottom text: "change" onClicked: { var num = Math.round(Math.random() * 100) console.log(num) dynamicObj.setProperty("one",num) } } }
main.cpp:
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQmlContext> class DynObj : public QObject { Q_OBJECT public: Q_INVOKABLE bool setProperty(QString name, const QVariant &value) {return QObject::setProperty(name.toUtf8(),value);} Q_INVOKABLE QVariant property(QString name) const {return QObject::property(name.toUtf8());} private: bool event(QEvent *event) { if (event->type() == QEvent::DynamicPropertyChange) { QDynamicPropertyChangeEvent *const propEvent = static_cast<QDynamicPropertyChangeEvent*>(event); QString propName = propEvent->propertyName(); emit propertyChanged(propName); } return QObject::event(event); } signals: void propertyChanged(QString name); }; int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); QQmlApplicationEngine engine; DynObj dynamicObj; engine.rootContext()->setContextProperty("dynamicObj", &dynamicObj); dynamicObj.setObjectName("dynamicObj"); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; return app.exec(); } #include "main.moc"
To work it creates a C++ QObject derived object that adds a couple of invokable methods to allow adding dynamic properties via QML. It also add a signal that fires whenever a property is updated. This is done by capturing the property changed event.
In the QML I create a map of "dynamic" properties represented by plist. I capture the signal from the C++ object and have it update the plist when a property changes in the C++ object. This then calls the function plistChanged which notifies all the QML objects that depend upon values in the plist to be updated.
To initiate a property change I set the property on the C++ object. The event fires on the object, which in turn updates the plist and forces the QML objects to update.
The biggest limitation with this I think is that as plist grows updates will affect updates to more and more objects. So I don't think it scales well. I also don't know if this is any better than just using a list model or database backend. I wrote this as more of a "can it be done?" Though it might be useful for something.
Any thoughts for improvement/refinement? I am very well aware it could be a misguided approach to begin with. Muahahahahaha!