QtObject instantiated by QML and it's parent
-
-
Hi,
when I have a custom component written in C++ and instantiated in QML, it's constructor is called with parent = nullptr. But later on the parent was set somehow. Is there any signal I can connect to, telling me the parent has been set?
Regards,
Stephan@DuBu said in QtObject instantiated by QML and it's parent:
when I have a custom component written in C++ and instantiated in QML, it's constructor is called with parent = nullptr. But later on the parent was set somehow. Is there any signal I can connect to, telling me the parent has been set?
Per default, the QML engine take ownership over QObject which don't have a parent (cf https://doc.qt.io/qt-5/qtqml-cppintegration-data.html).
AFAIK, there is no signal emitted on parent changes.
-
So it seems I could reimplement "bool Object::event(QEvent *)" and check for QEvent::ParentChange.
Unfortunately there's no QEvent::ParentChange and QEvent::ParentAboutToChange, although the parent changes.@DuBu said in QtObject instantiated by QML and it's parent:
So it seems I could reimplement "bool Object::event(QEvent *)" and check for QEvent::ParentChange.
Unfortunately there's no QEvent::ParentChange and QEvent::ParentAboutToChange, although the parent changes.These events only apply to QWidget derived objects.
QEvent::ChildAdded is generated for QObject parent changes, although it's sent to the parent rather than the child.
QQuickItem has a parentChanged signal.
-
Can you describe us your usecase a bit more @DuBu to figure out if there's a possible alternative?
@GrecKo The component need to access it's parent component to do it's job. But I don't know how to access the parent when the "parent" argument of the constructor is NULL and there's no signal the component could catch when the parent actually has been set. I could use a timer, but that's not way i think it should work.
-
@GrecKo The component need to access it's parent component to do it's job. But I don't know how to access the parent when the "parent" argument of the constructor is NULL and there's no signal the component could catch when the parent actually has been set. I could use a timer, but that's not way i think it should work.
@DuBu said in QtObject instantiated by QML and it's parent:
The component need to access it's parent component to do it's job. But I don't know how to access the parent when the "parent" argument of the constructor is NULL and there's no signal the component could catch when the parent actually has been set. I could use a timer, but that's not way i think it should work.
If I am remember right your use case: on create QObject based classes which are used from QML.
And you want to execute "something" when the instance is initialized by the QML engine.
My suggestion would be to useComponent.onCompleted
to do that.
Supposing your class is calledMyItem
:MyItem { Component.onCompleted: { // do stuff here } }
-
@DuBu said in QtObject instantiated by QML and it's parent:
The component need to access it's parent component to do it's job. But I don't know how to access the parent when the "parent" argument of the constructor is NULL and there's no signal the component could catch when the parent actually has been set. I could use a timer, but that's not way i think it should work.
If I am remember right your use case: on create QObject based classes which are used from QML.
And you want to execute "something" when the instance is initialized by the QML engine.
My suggestion would be to useComponent.onCompleted
to do that.
Supposing your class is calledMyItem
:MyItem { Component.onCompleted: { // do stuff here } }
@KroMignon I want to do it in c++ and I want to preferably access the parent before any property got set/bound.
-
@KroMignon I want to do it in c++ and I want to preferably access the parent before any property got set/bound.
@DuBu said in QtObject instantiated by QML and it's parent:
I want to do it in c++ and I want to preferably access the parent before any property got set/bound.
Sound complicated to me, AFAIK the instance will send an
QEvent::ChildAdded
/QEvent::ChildRemoved
event on parent changes but only to the new/previous parent instance.I think, you have to redesign your application.
-
Here's my use case:
ParentQObjectComp { MyInstantiator { ChildQObjectComp {} } }
So all 3 components are written in c++ and derived from QObject. Now in MyInstantiator I want to add the ChildQObjectComp to the ParentQObjectComp which is the parent of MyInstantiator. The only way I can think of is to access the parent in the moment the ChildQObjectComp get's added to MyInstantiator.
-
Here's my use case:
ParentQObjectComp { MyInstantiator { ChildQObjectComp {} } }
So all 3 components are written in c++ and derived from QObject. Now in MyInstantiator I want to add the ChildQObjectComp to the ParentQObjectComp which is the parent of MyInstantiator. The only way I can think of is to access the parent in the moment the ChildQObjectComp get's added to MyInstantiator.
@DuBu said in QtObject instantiated by QML and it's parent:
So all 3 components are written in c++ and derived from QObject. Now in MyInstantiator I want to add the ChildQObjectComp to the ParentQObjectComp which is the parent of MyInstantiator. The only way I can think of is to access the parent in the moment the ChildQObjectComp get's added to MyInstantiator.
I am pretty sure that
MyInstantiator
instance will receive anQEvent::ChildAdded
event fromChildQObjectComp
.
AndParentQObjectComp
instance same event fromMyInstantiator
instance
Is that not enough for you? -
@DuBu said in QtObject instantiated by QML and it's parent:
So all 3 components are written in c++ and derived from QObject. Now in MyInstantiator I want to add the ChildQObjectComp to the ParentQObjectComp which is the parent of MyInstantiator. The only way I can think of is to access the parent in the moment the ChildQObjectComp get's added to MyInstantiator.
I am pretty sure that
MyInstantiator
instance will receive anQEvent::ChildAdded
event fromChildQObjectComp
.
AndParentQObjectComp
instance same event fromMyInstantiator
instance
Is that not enough for you?@KroMignon When MyInstantiator receives the ChildAdded event for ChildQObjectComp it need's to access it's parent. But MyInstantiator doesn't know it's parent cause there's no ParentChange event. The ChildAdded event in ParentQObjectComp for MyInstantiator is not useful cause it doesn't know anything about a MyInstantiator and therefor it doesn't know what to do with the event.
-
@KroMignon When MyInstantiator receives the ChildAdded event for ChildQObjectComp it need's to access it's parent. But MyInstantiator doesn't know it's parent cause there's no ParentChange event. The ChildAdded event in ParentQObjectComp for MyInstantiator is not useful cause it doesn't know anything about a MyInstantiator and therefor it doesn't know what to do with the event.
@DuBu said in QtObject instantiated by QML and it's parent:
When MyInstantiator receives the ChildAdded event for ChildQObjectComp it need's to access it's parent. But MyInstantiator doesn't know it's parent cause there's no ParentChange event. The ChildAdded event in ParentQObjectComp for MyInstantiator is not useful cause it doesn't know anything about a MyInstantiator and therefor it doesn't know what to do with the event.
Again, as I wrote before, you have to redesign your code. It is not possible to handle this in C++ directly.
You could perhaps use eventFilter and "catch" allQEvent::ChildAdded
and check if the receiver is anMyInstantiator
:class ParentFilter : public QObject { Q_OBJECT public: explicit ParentFilter (QObject *parent = 0): QObject(parent) {} public: bool eventFilter(QObject *object, QEvent *event) { if (event->type() == QEvent::ChildAdded ) { QChildEvent*childEvent = static_cast<QChildEvent*>(event); MyInstantiator* o = qobject_cast<MyInstantiator*>(childEvent->child()); if(o) { // do stuff here } } return QObject::eventFilter(object,event); } };
Then register the filter:
qApp->installEventFilter(new ParentFilter(qApp));
-
@DuBu said in QtObject instantiated by QML and it's parent:
When MyInstantiator receives the ChildAdded event for ChildQObjectComp it need's to access it's parent. But MyInstantiator doesn't know it's parent cause there's no ParentChange event. The ChildAdded event in ParentQObjectComp for MyInstantiator is not useful cause it doesn't know anything about a MyInstantiator and therefor it doesn't know what to do with the event.
Again, as I wrote before, you have to redesign your code. It is not possible to handle this in C++ directly.
You could perhaps use eventFilter and "catch" allQEvent::ChildAdded
and check if the receiver is anMyInstantiator
:class ParentFilter : public QObject { Q_OBJECT public: explicit ParentFilter (QObject *parent = 0): QObject(parent) {} public: bool eventFilter(QObject *object, QEvent *event) { if (event->type() == QEvent::ChildAdded ) { QChildEvent*childEvent = static_cast<QChildEvent*>(event); MyInstantiator* o = qobject_cast<MyInstantiator*>(childEvent->child()); if(o) { // do stuff here } } return QObject::eventFilter(object,event); } };
Then register the filter:
qApp->installEventFilter(new ParentFilter(qApp));
@KroMignon That's a nice approach. Thanks for the code!
I recon in my special use case it's sufficient to access the parent in the event handler for ChildAdded in MyInstantiator, which is hopefully already set at that time.
Thanks for the hints to ChildAdded/ChildRemoved events. -
What about overriding QQmlParserStatus::classBegin and using QObject::parent() to retrieve the parent?
Another way to do it would just be to add a property in MyInstantiator to specify the ParentQObjectComp, the advantage is that you can define an Instantiator outside of the QML hierarchy of ParentQObjectComp.