'How can I give a Qt QML item a property that doesn't notify when it changes?
I (very) occasionally find myself needing to add a property to an item that isn't bindable in other expressions, that is to say that when its value changes, it doesn't notify anything that uses its value and thus doesn't cause expressions to be re-evaluated. The point of this is to have essentially what is a pure state variable that can't get itself involved in binding loops.
As a concrete example:
Item
{
property string state: ""
visible:
{
if(some_condition)
{
state = "foo";
return true;
}
if(state === some_other_external_state)
return true;
state = "";
return false;
}
}
In this case where some_condition
becomes true the visible
property sets state
and a binding loop occurs since visible
depends on the value of state
. If the state
property didn't bind and was, as its name implies, purely a state variable, this loop is avoided.
Solution 1:[1]
One hacky solution that I've used before is:
Item
{
property var state: [""]
visible:
{
if(some_condition)
{
state[0] = "foo";
return true;
}
if(state[0] === some_other_external_state)
return true;
state[0] = "";
return false;
}
}
This works because array properties don't notify when the contents of the array change, they only notify when the array itself changes. It's not pretty, but it works.
Solution 2:[2]
You cannot create non-bindable property in QML. But you can control what bindings will be created.
By design property bindings should not change values of other properties. This is the source of problem in code sample you provided. There is not enough details to provide full solution but consider this pseudo code:
Item {
// Item has state property already - you should not redefine it
// property string state: ""
visible: state !== "" // or whatever else is correct, but keep it simple
// Optionally:
onVisibleChanged: {
// Any extra operations that should be done
// when item is being shown or hidden
// But you should not change state variable here!
}
// Monitor all events that should change state and keep it up to date
// Usually Qt will already have a signal notifying about particular change
// or you can define signals you need and emit in proper places
Connections {
target: other_object
onSignalForSomeSpecificEvent: state = "bar"
}
// Some conditions you can define in declarative form
// Suitable for condition depending on other properties
property bool someCondition
onSomeConditionChaged: state = 'foo'
}
A lot depends on particular design but 2 rules of thumb:
- bindings should not alter other properties
- use signal handlers to avoid unwanted bindings
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Tim Angus |
Solution 2 | Åukasz Korbel |