Signaling to users of component that binding a property is not safe



  • I found the following QML component here:

    import QtQuick 2.0
    
    Rectangle {
        id: myRect
        width: 100; height: 100
        color: "black"
    
        MouseArea {
            id: mouseArea
            anchors.fill: parent
            onClicked: myRect.state == 'clicked' ? myRect.state = "" : myRect.state = 'clicked';
        }
    
        states: [
            State {
                name: "clicked"
                PropertyChanges { target: myRect; color: "red" }
            }
        ]
    }
    

    Let's call it "MyRect.qml". Since MyRect overrides the state property, binding it to a property won't work:

    Item {
        id: root
    
        MyRect {
            id: inner
    
            state: root.state // not safe
        }
    }
    

    Assigning it will however work:

    Item {
        id: root
    
        onStateChanged: inner.state = root.state // safe
    
        MyRect {
            id: inner
        }
    }
    

    On the other hand both binding and assigning would be safe for the property width of MyRect.qml.

    How can a user of MyRect.qml know which properties are safe to bind and which are not without having to examine the source code?



  • How can u say that this is 'safe ' ?? why ?

    Item {
    id: root

    onStateChanged: inner.state = root.state // safe
    
    MyRect {
        id: inner
    }
    

    }

    if MyRect.qml dont has same state names that 'root' how it can work ?



  • @LeLev For the purpose of the example, it is the case that, they are the same. This issue is not what the question is about.



  • This post is deleted!


  • @Uldall I can't find a way to do that except documentation. QML isn't good for "safe" programming, whatever that means. Even javascript itself isn't type safe or doesn't have "private" things (contra C++), and QML is built on top of it. It might, just might, be possible to do something inside C++ implementation of QML - in Component.onCompleted you could call a custom C++ function which checks as much as can be checked with the public part of the engine, but I don't know if it's possible to find bindings with it.



  • @Eeli-K That is the same conclusion that I have come to, i.e. that documentation is the only way of solving this. I hope that The Qt Company will look into fixing this issue at some point.



  • @Uldall Other developers or the company may have different opinions on this; mine is that it's not an issue to be fixed. If you write all of the code you should know what you're doing, and if there's a reusable component made by one party and used by another it should be documented and/or the code should be available to read. Think about javascript (on which QML is based): there's no privacy nor type safety, you can do basically anything with any object if you want to, safety is about coding practices, documentation etc. Still there exist even large reusable libraries which work (relatively) as well as C++ libraries. Same thing with python.



  • @Uldall Just when I said what I said, KDAB published a blog post: https://www.kdab.com/new-qt-5-10-diagnostics-breaking-qml-bindings/



  • The first example from @Uldall does work for me, it seems pretty safe, the following snippet shows that changing the state from root affects inner. Please mark this tread has solved if your doubts have been cleared.

    Item {
            id: root
    
            MyRect {
                id: inner
                state: root.state // yes it's safe, but this binding will be broke from inner state assignement
            }
    
            MouseArea {
                anchors.top: inner.bottom
                anchors.bottom: parent.bottom
                anchors.left: parent.left
                anchors.right: parent.right
                onClicked: root.state == 'clicked' ? root.state = "" : root.state = 'clicked';
            }
        }
    

    @Eeli-K nice reading from Kdab. For the sake of completeness it should be noted that if someone on purpose breaks the bindings, it can be defined again from a javascript block http://doc.qt.io/qt-5/qtqml-syntax-propertybinding.html#creating-property-bindings-from-javascript



  • Also please note that while it is not possible directly to change the state from both root and inner without breaking the bindind, in this particular case you can get away with a hack using a intermediate property isClicked:

    Rectangle {
    id: myRect
    width: 100; height: 100
    color: "black"
    
    property bool isClicked: true
    state: isClicked ? "clicked" : ""
    
    MouseArea {
        id: mouseArea
        anchors.fill: parent
        onClicked: {
            console.log("click from inner")
            isClicked = !isClicked
        }
    }
    
    states: [
        State {
            name: "clicked"
            PropertyChanges { target: myRect; color: "red" }
        }
      ]
    }
    

    ´

    Item {
        id: root
        anchors.fill: parent
    
        MyRect {
            id: inner
            
        }
    
        MouseArea {
            anchors.top: inner.bottom
            anchors.bottom: parent.bottom
            anchors.left: parent.left
            anchors.right: parent.right
    
            onClicked: {
                console.log("click from root")
                inner.isClicked = !inner.isClicked
            }
        }
    }

Log in to reply
 

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