How to make a connection to Component destruction() signal from cpp side
-
Hello,
Connecting Component destruction() signal to cpp slot from qml side is quite simple -
Component.onDestruction: mySlot().But I'm intrested how to catch this signal or make a connection from cpp side.
@Eligijus
since a QQuickItem inherits QObject simply connect to QObject::destroyed() signal -
@Eligijus
since a QQuickItem inherits QObject simply connect to QObject::destroyed() signal@raven-worx Component destruction() signal is emited when object property values are still valid/not destroyed. As I still want to access some property data from this object, both QObject::destroyed() and ~QObject() get called too late.
-
@raven-worx Component destruction() signal is emited when object property values are still valid/not destroyed. As I still want to access some property data from this object, both QObject::destroyed() and ~QObject() get called too late.
@Eligijus
The problem is that the attached property of Component (private QQmlComponentAttached class) hooks directly into the QML engine internals.
Deleting an item from C++ always has the "drawback" that the derived destructor is called first (due to the virtual destructor of QObject).
So i would expect that the Component.onDestruction only works for QML items with QML ownership.About what items are we actually talking? Whats the use case exactly?
-
@Eligijus
The problem is that the attached property of Component (private QQmlComponentAttached class) hooks directly into the QML engine internals.
Deleting an item from C++ always has the "drawback" that the derived destructor is called first (due to the virtual destructor of QObject).
So i would expect that the Component.onDestruction only works for QML items with QML ownership.About what items are we actually talking? Whats the use case exactly?
@raven-worx My use case is that I want to save property array value to file upon destruction.
Let's say I have Class Testclass Test : public QObject { Q_OBJECT public: explicit Test(QObject *parent = nullptr); ~Test(); Q_INVOKABLE void store(); };store method for simplicity currently prints value to debug console
void Test::store() { const QMetaObject *o = metaObject(); int offset = o->propertyOffset(); int count = o->propertyCount(); for (int i = offset; i < count; ++i) { QMetaProperty metaProperty = o->property(i); QVariant defaultValue = property(metaProperty.name()); if (defaultValue.userType() == qMetaTypeId<QJSValue>()) defaultValue = defaultValue.value<QJSValue>().toVariant(); qDebug() << metaProperty.name() << defaultValue; } }I create Test in qml:
Test { id: t property var foo: [100, 200, 300] }And if store() is called in constructor here's the output:
foo QVariant(Invalid)But if I connect store() to Component destruction() in qml I get my expected output:
foo QVariant(QVariantList, (QVariant(int, 100), QVariant(int, 200), QVariant(int, 300)))My problem is that I don't want to add additional code to qml side and make a connection from cpp side because there are many
Testobjects created in qml. -
@raven-worx My use case is that I want to save property array value to file upon destruction.
Let's say I have Class Testclass Test : public QObject { Q_OBJECT public: explicit Test(QObject *parent = nullptr); ~Test(); Q_INVOKABLE void store(); };store method for simplicity currently prints value to debug console
void Test::store() { const QMetaObject *o = metaObject(); int offset = o->propertyOffset(); int count = o->propertyCount(); for (int i = offset; i < count; ++i) { QMetaProperty metaProperty = o->property(i); QVariant defaultValue = property(metaProperty.name()); if (defaultValue.userType() == qMetaTypeId<QJSValue>()) defaultValue = defaultValue.value<QJSValue>().toVariant(); qDebug() << metaProperty.name() << defaultValue; } }I create Test in qml:
Test { id: t property var foo: [100, 200, 300] }And if store() is called in constructor here's the output:
foo QVariant(Invalid)But if I connect store() to Component destruction() in qml I get my expected output:
foo QVariant(QVariantList, (QVariant(int, 100), QVariant(int, 200), QVariant(int, 300)))My problem is that I don't want to add additional code to qml side and make a connection from cpp side because there are many
Testobjects created in qml.@Eligijus
Try this approach:if( QObject *attached = qmlAttachedPropertiesObject<QQmlComponent>(this, true) ) connect( attached, SIGNAL(destruction()), this, SLOT(store()) ); // explicitly using the old syntax here, since QQmlComponentAttached is a private typeNote the
qmlAttachedPropertiesObject()call with the second parameter set totrueto create the attached object if it doesn't exist yet. -
@Eligijus
Try this approach:if( QObject *attached = qmlAttachedPropertiesObject<QQmlComponent>(this, true) ) connect( attached, SIGNAL(destruction()), this, SLOT(store()) ); // explicitly using the old syntax here, since QQmlComponentAttached is a private typeNote the
qmlAttachedPropertiesObject()call with the second parameter set totrueto create the attached object if it doesn't exist yet.@raven-worx That works. Thanks for answer and comment why use an old connect sytax there very informative.
I ended up putting this code snippet inside componentComplete() method inherited from QQmlParserStatus because putting it directly in constructor didn't work. -
@raven-worx That works. Thanks for answer and comment why use an old connect sytax there very informative.
I ended up putting this code snippet inside componentComplete() method inherited from QQmlParserStatus because putting it directly in constructor didn't work.@Eligijus said in How to make a connection to Component destruction() signal from cpp side:
Thanks for answer and comment why use an old connect sytax there very informative.
Just to point out the alternative to the old connect syntax:
the connection could also be done by searching for the corresponding QMetaMethod in the QMetaObject of the attached object and connect it.
But it's way shorter with the old syntax.