Item's enabled and visible properties and QML binding
-
Hi all,
In the description of the "enabled" property of QML Item element there is the following paragraph:
Setting this property directly affects the enabled value of child items. When set to false, the enabled values of all child items also become false. When set to true, the enabled values of child items are returned to true, unless they have explicitly been set to false.
(and the same is stated in the description of "visible" property). I wonder, does it break property bindings? I wrote a small test:
import QtQuick 2.12 import QtQuick.Controls 2.5 import QtQuick.Window 2.12 Window { visible: true width: 640 height: 480 title: qsTr("Hello World") Column { id: column anchors.centerIn: parent Text { id: text text: "TEXT" states: [ State { name: "visibleBind" PropertyChanges { target: text visible: timer.textVisibility enabled: timer.textVisibility } }, State { name: "visibleForceUnbind" PropertyChanges { target: text visible: timer.textVisibility enabled: timer.textVisibility } } ] onVisibleChanged: { console.log("VISIBLE: " + visible); } onEnabledChanged: { console.log("ENABLED: " + enabled); } } } Row { anchors.bottom: parent.bottom anchors.horizontalCenter: parent.horizontalCenter Button { text: "VISIBILITY" onClicked: { column.visible = !column.visible; column.enabled = !column.enabled; } } Button { text: "BIND" onClicked: { text.state = "visibleBind"; } } Button { text: "BREAK" onClicked: { text.state = "visibleForceUnbind"; text.visible = false; text.enabled = false; } } } Timer { id: timer interval: 1000 repeat: true running: true property bool textVisibility: false onTriggered: { textVisibility = !textVisibility; } } }
and it looks like this behaviour doesn't break bindings (changing of property values stops after clicking on "VISIBILITY" button, but resumes after clicking on it again), but is this a part of contract? I mean, is this a documented behaviour and not expected to change between versions? The paragraph quoted above is not very clear on this point.
Thanks in advance for your help.
-
OK, it looks like I got this. Roughly speaking, there are two states of any property: static value and binding. If property contains static value, then state machinery remember it as static value (and it doesn't matter, was this value inherited from parent or not, it always just remember current value as static value). If property contains binding, then it will be remembered as binding (and state machinery doesn't care about momentary resulting value of this binding).
-
It looks like the better wording would be "unless this property have explicitly been set to specific value in child item, in which case it will return to this value" or something like this. Not just in terms of static true/false values, which looks misleading.
-
OK, here is another one puzzle:
import QtQuick 2.12 import QtQuick.Controls 2.5 import QtQuick.Window 2.12 Window { visible: true width: 640 height: 480 title: qsTr("Hello World") Column { id: column anchors.centerIn: parent Text { id: text text: "TEXT" visible: true states: [ State { name: "setVisible" PropertyChanges { target: text visible: true } }, State { name: "restoreVisible" } ] onVisibleChanged: { console.log("VISIBLE: " + visible); } } } Row { anchors.bottom: parent.bottom anchors.horizontalCenter: parent.horizontalCenter spacing: 16 Button { text: "TOGGLE COLUMN VISIBILITY" onClicked: { column.visible = !column.visible; } } Button { text: "SET TEXT VISIBILITY" onClicked: { text.state = "setVisible"; } } Button { text: "RESTORE TEXT VISIBILITY" onClicked: { text.state = "restoreVisible"; } } } Timer { id: timer interval: 1000 repeat: true running: true property bool textVisibility: false onTriggered: { textVisibility = !textVisibility; } } }
- Suppose that we run this app and then click on "TOGGLE COLUMN VISIBILITY" button. Text.visible become false.
- Then we click on "SET TEXT VISIBILITY" button. Text goes into "setVisible" state and remember that previous state included visible=false.
- Then we click on "TOGGLE COLUMN VISIBILITY" button again. Column become visible and text too.
- Then we click on "RESTORE TEXT VISIBILITY" button. Text goes from "setVisible" state (resetting visible property to memorized value, which is false) to "restoreVisible" state and become invisible.
So far so good. Then we make following changes to our code:
Text { id: text text: "TEXT" - visible: true + visible: timer.textVisibility
and repeat our experiments:
- Run this app and see a blinking text, which is expected.
- Click on "TOGGLE COLUMN VISIBILITY" button. Text.visible become false. OK, this is expected too.
- Then we click on "SET TEXT VISIBILITY" button. Text goes into "setVisible" state and should remember that previous state included visible=false (just like in previous case, as I think).
- Then we click on "TOGGLE COLUMN VISIBILITY" button again. Column become visible and text too (but it doesn't blink). Just as expected.
- Then we click on "RESTORE TEXT VISIBILITY" button. Text goes from "setVisible" state and should reset visible property to false (which was memorized at step 3) to "restoreVisible" state and become invisible, but it's not the case! Instead it start blinking again, so it looks like that on step 3 it remember property binding instead of actual value.
Why such a discrepancy here?
-
OK, it looks like I got this. Roughly speaking, there are two states of any property: static value and binding. If property contains static value, then state machinery remember it as static value (and it doesn't matter, was this value inherited from parent or not, it always just remember current value as static value). If property contains binding, then it will be remembered as binding (and state machinery doesn't care about momentary resulting value of this binding).