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: rootonStateChanged: 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.
-
@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.
@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.
-
@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.
-
@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.
-
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 } } }