[Solved] Component::createObject(): bindings don't work



  • Hello all;
    this is to explain a problem with Dynamic QML Object Creation and the bindings which should be created when calling the Component::createObject() method.

    I could create 2 rects and bind a property of the second one to some property of the first one. But when creating the second rect in a dynamic manner, the binding is not well stablished (ie. changes in the first rect don't apply to the second one).

    This is a minimal code sample:

    @
    import QtQuick 2.0

    Item {
    id: window
    width: 100; height: 100

    Rectangle {
        id: mainRect
        width: 30; height: 30
    }
    
    Item { id: myContainer }
    
    Component {
        id: myComponent
        Rectangle {
            width: 50; height: 50
            color: "red"
            onWidthChanged: console.log("[Rectangle onWidthChanged()]", "width", width)
        }
    }
    
    function loadItems() {
        var item = myComponent.createObject(myContainer, {"width": mainRect.width})
        if (item == null) {
            console.log("[loadItems()]", "ERROR", "Component::createObject()")
        }
    }
    
    Component.onCompleted: {
        loadItems()
        mainRect.width = 31
        mainRect.width = 32
        mainRect.width = 33
    }
    

    }
    @

    Expected output:
    @
    [Rectangle onWidthChanged()] width 30
    [Rectangle onWidthChanged()] width 31
    [Rectangle onWidthChanged()] width 32
    [Rectangle onWidthChanged()] width 33
    @

    Obtained output:
    @
    [Rectangle onWidthChanged()] width 30
    @

    I'd like to know if this problem is due to my misuse or it is a bug and I should register it in the bug tracker.
    Thanks!


    EDIT: solution found:
    @
    var item = myComponent.createObject(myContainer, {"width": Qt.binding(function(){ return mainRect.width })})
    @



  • The following line doesn't result a property binding but a property value set. It is different.
    @
    var item = myComponent.createObject(myContainer, {"width": mainRect.width})
    @

    What would result property binding would be to set it right from the Component definition.

    @
    import QtQuick 2.0

    Item {
        id: window
        width: 100; height: 100
     
        Rectangle {
            id: mainRect
            width: 30; height: 30
        }
     
        Item { id: myContainer }
     
        Component {
            id: myComponent
            Rectangle {
                width: mainRect.width; height: 50
                color: "red"
                onWidthChanged: console.log("[Rectangle onWidthChanged()]", "width", width)
            }
        }
     
        function loadItems() {
            var item = myComponent.createObject(myContainer)
            if (item == null) {
                console.log("[loadItems()]", "ERROR", "Component::createObject()")
            }
        }
     
        Component.onCompleted: {
            loadItems()
            mainRect.width = 31
            mainRect.width = 32
            mainRect.width = 33
        }
    }
    

    @



  • Well both the intuition and the docs seem to say that a value binding (not assignment) is what should happen in my previous code.

    I guess I should report a bug in documentation, as the QML Component docs state that:

    bq. Component::createObject [...] accepts an optional properties argument [...] allows property bindings to be set up before the object is createdbq.

    Source(s):
    http://qt-project.org/doc/qt-5.0/qtqml/qml-qtquick2-component.html#createObject-method
    and
    http://doc-snapshot.qt-project.org/5.0/qtqml/qml-qtquick2-component.html#createObject-method


    Thanks for a proposed solution, but for me, it defeats completely the whole purpose of doing Dynamic creation of objects. This was a minimal example but lets say instead of 1 "mainRect" you have 30 rectangles, and the one to use for binding is whichever one the user clicked over.

    Please if there is an obvious solution to this let me know, I will keep on trying to find the best way of doing this in a proper QML way and report here if one is found.



  • You can set up bindings in the initial property values definition. However, the syntax is slightly different.
    In QtQuick1, you use the function assignment syntax. In QtQuick2, you use the Qt.binding() syntax.

    example:
    @
    import QtQuick 1.1
    var item = myComponent.createObject(myContainer, {"width": (function(){ return mainRect.width})})
    @

    or

    @
    import QtQuick 2.0
    var item = myComponent.createObject(myContainer, {"width": Qt.binding(function(){mainRect.width})})
    @

    Cheers,
    Chris.



  • Thank you very much!
    It works without problems!

    I had tried with the old QtQuick1 way, not the new QtQuick2 way.



  • THX, great! That's what I looked for! ;-)


Log in to reply
 

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