Is it safe to set QObject::setParent for qml object with JavaScriptOwnership?
-
wrote on 18 Jun 2023, 18:02 last edited by
Hi, I have specific requirement that QML_ELEMENT class should be instaniated on c++ side and is used/returned to QML. In this example according to documentation returned object is owned by javascript (which is what I want).
Q_INVOKABLE ButtonModel *getModel() { return new ButtonModel(); }
On QML side this Object is used together with some visual element (and so is made a property). Example:
Component { id: _dynamicBtn Button { required property ButtonModel model text: "hello" } }
My requirement is that ButtonModel is destroyed together with its visual element. Unfortunatelly, because of garbage collection ButtonModel is destroyed some time in future, which is not good.
If I expose and set manually parent(owner), then everything seem to work as expected.// ButtonModel Q_INVOKABLE void setOwner(QObject *parent) { QObject::setParent(parent); }
// qml let mod = _btnMngr.getModel(); let o = _dynamicBtn.createObject(_flow, {model: mod}); mod.setOwner(o);
I am just worried if this is ok, but can't find confirmation if this is safe. I am afraid that if parent later is changed in c++, then Qml Engine doesn't know about it. By testing seems to be fine.
-
Hi, I have specific requirement that QML_ELEMENT class should be instaniated on c++ side and is used/returned to QML. In this example according to documentation returned object is owned by javascript (which is what I want).
Q_INVOKABLE ButtonModel *getModel() { return new ButtonModel(); }
On QML side this Object is used together with some visual element (and so is made a property). Example:
Component { id: _dynamicBtn Button { required property ButtonModel model text: "hello" } }
My requirement is that ButtonModel is destroyed together with its visual element. Unfortunatelly, because of garbage collection ButtonModel is destroyed some time in future, which is not good.
If I expose and set manually parent(owner), then everything seem to work as expected.// ButtonModel Q_INVOKABLE void setOwner(QObject *parent) { QObject::setParent(parent); }
// qml let mod = _btnMngr.getModel(); let o = _dynamicBtn.createObject(_flow, {model: mod}); mod.setOwner(o);
I am just worried if this is ok, but can't find confirmation if this is safe. I am afraid that if parent later is changed in c++, then Qml Engine doesn't know about it. By testing seems to be fine.
wrote on 19 Jun 2023, 00:08 last edited by@chocis said in Is it safe to set QObject::setParent for qml object with JavaScriptOwnership?:
Hi, I have specific requirement that QML_ELEMENT class should be instaniated on c++ side and is used/returned to QML. In this example according to documentation returned object is owned by javascript (which is what I want).
Q_INVOKABLE ButtonModel *getModel() {
While this is a quick and easy solution, I generally find it to be more difficult to reason about. It's a pattern that seems to turn up frequently in projects where contributors are not comfortable with QML, which leads to other issues. My suggestion is to register the type to the QML engine, and instantiate it as any other QML component. If some initialization action needs to be delayed, use a property change to trigger that action.
If I expose and set manually parent(owner), then everything seem to work as expected.
// ButtonModel Q_INVOKABLE void setOwner(QObject *parent) { QObject::setParent(parent); }
This "works" because the garbage collection engine won't touch it. The normal QObject destructor of the parent item will delete it and all other QObject children. The same thing will happen if ownership is left as CppOwnership.
https://doc.qt.io/qt-6/qjsengine.html#ObjectOwnership-enum:
The object is owned by JavaScript. When the object is returned to the JavaScript memory manager as the return value of a method call, the JavaScript memory manager will track it and delete it if there are no remaining JavaScript references to it and it has no QObject::parent().
-
1/2