QDeclarativeItem creation observing



  • Hi,
    is there a way to observe when a new declarative item was dynamically created with Qt.createComponent()?
    I would like to track these changes, similar to what QDeclarativeViewInspector or QDeclarativeDebugService does, but I could not find a public API that allows me to achieve it.

    One approach I tried was listening to childrenChanged signal, but the problem there is it gets called before the properties of the created item are valid, and since componentComplete() is not a public function I could not determine whether the item was successfully created or not.

    I know I could implement own items derived from QDeclarativeItem and then override the protected function itemChanged and responding to ItemChildAddedChange, but I would prefer a solution without custom items just introduced for the introspection purpose.

    I appreciate your help,
    cheers



  • hello,

    In the documentation componentComplete () is tagged as pure virtual, so if you instancied it, didn't you get what you need?

    dmcr



  • No I dont, because it is only usable for custom items derived from QDeclarativeItem where you could overwrite componentComplete() as you have full control of it. But since I cant change the source of the provided qml items (like QDeclarativeImage), componentComplete() cant be used for observing non-custom items in the qml tree.

    chris



  • Ha yes you are right :)
    On solution could be to put some code in Component.onCompleted :.....inside the component dynamicly created, but i imagine this is the same problem for you, you want to do this for all items.



  • you're right ;)



  • ... I am looking for a non-intrusive way to observe existing declarative items, so without having to introduce custom-derived QDeclarativeItem classes and no custom components written in QML (where I could use your suggestion with onCompleted, which is basically the same like overriding componentComplete() in C++ classes).



  • After further investigation, I can imagine to get this working by connecting the Component.onCompleted signal handler every time a childrenChanged-signal is received from any observed item in the qml tree.. But how can I connect the signal onCompleted from the attached component "Component" from C++ with a slot of my choice?

    As this works:
    @Item {
    Component.onCompleted: ...
    }@

    is there a way to call something like this:

    @connect(declarativeItem, SIGNAL(?what goes in here - something like Component::onCompleted()?), observingObject, SLOT(myDeclarativeItemCompletedSlot());@



  • Connecting the completed-signal of the attached component of a QDeclarativeItem works like this:
    1.) Iterate over all children of the item and find the one inheriting QDeclarativeComponentAttached
    2.) connect the completed-signal with any other slot you like

    So something like this:
    @
    QObjectList objectList = children();
    for(int j=0;j<objectList.length(); j++) {
    QObject *child = objectList.at(j);
    qDebug() << "child" << child->objectName() << ":" << child;
    if(child->inherits("QDeclarativeComponentAttached")) {

            QObject *attachedComponent = child;
    
            qDebug() << "attachedComponent:" << attachedComponent << "of child:" << child->objectName();
            
            bool connectionSuccess = connect( attachedComponent, SIGNAL(completed()), this, SLOT(childCompleted()) );@
    

    The order the custom slot childCompleted() gets called, is AFTER the JavaScript handler code in Component.onCompleted: {...} was executed



  • Hello,

    I'm looking for similar way for the attached properties, to get notified when the attachee is completed. Searching the forum I found your solution, however this works only when your component has "Component.onCompleted:" declared.

    Is there any other way to check whether a component is completed from dynamically created items or from attached properties?

    Thanks!
    Cheers



  • Hi,
    not that I'm aware of - I was not aware that it only works when Component.onCompleted() is declared; appearently, I always declared it..

    What you could try as well, is this approach:
    Call qmlRegisterType() from C++ and register your own Item under the same name you want to track for completion. I.e. when you want to observe all "Item" components, create an own class inheriting from QDeclarativeItem and register that under the name "Item". That way, your QDeclarativeItem gets created whenever an Item appears in QML, and you can overwrite componentComplete.

    However, that approach is not possible with private classes like QDeclarativeImage or QDeclarativeRectangle.

    Does that help for your use-case?

    If you find another approach, you're very welcome to share it.

    cheers



  • Well, I tried that, the problem is that I need to catch completion of every attachee, like Text, Rectangle, etc. I also tried to derive my object from QQmlParserStatus, but these attached objects do not get the componentComplete() called.

    I'll keep hunting, till then will use your solution :) And let you know if I find something.

    cheers!



  • well, the pain here is that the order of the completion-calls is not defined in QML. Regarding the doc:
    bq. The order of running the onCompleted scripts is undefined.

    However, what this means is that within the same Qt version the order IS defined, but that may change with future Qt versions (I did not check on Qt5 for example, if it changed there).

    however, the C++ componentComplete order of the base item is the last one called, i.e. all children got called C++ their componentComplete() before and are fully initialized. With QML's Component.onCompleted() it's the other way around:
    base, child2, subchild2, child1, subchild1

    with this test scenario:

    @
    Item {
    id: base

    Item {
    id: child1
    Item { id: subchild1 }
    }

    Item {
    id: child2
    Item { id: subchild2 }
    }
    }
    @

    So it depends whether you depend on initialization in Component.onComplete - if you are not, you can just use the C++ componentComplete() function.



  • Luckily my attached properties do not depend on children initialization, so the solution is good enough at the moment. All I need to know is when the attachee reaches the point of being initialized, so I can trigger the logic I have in the attached property.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.