Reputation: 1738
I'd like to create a widget that has a value that can be bound to a value outside of itself, but can also internally set this value. A scenario I'd like to be able to support:
Point 5 does not seem possible when using only bindings. Here is an example where 'textItem' is our imaginary widget:
import QtQuick 2.7
import QtQuick.Controls 2.0
ApplicationWindow {
visible: true
width: 640
height: 480
property real externalValue: (Math.random()* 50).toFixed(0)
Timer {
running: true
repeat: true
interval: 1000
onTriggered: {
// Simulate externalValue changes out of our control
externalValue = (Math.random()* 50).toFixed(0)
}
}
Component.onCompleted: {
// Unknown external binding set by developer using textItem widget
textItem.text = Qt.binding(function(){return externalValue})
}
Column {
Text {
id: textItem
text: ""
property real internalValue: (Math.random()* 50).toFixed(0)
Binding on text {
id: binding
value: textItem.internalValue
when: false
}
}
Button {
text: "Change Internal Value"
onClicked: {
textItem.internalValue = (Math.random()* 50).toFixed(0)
binding.when = true
}
}
}
}
So textItem.text listens to the externalValue binding until a user interacts with the button, which then binds textItem.text to the user-set internal value. Assuming textEdit is a black-box widget, and it has no concept of externalValue before its runtime binding, is there any way for textEdit to internally listen to the overridden externalValue binding and restore it (by setting binding.when = false) the next time that externalValue is updated by the timer?
One way to make the scenario work would be to use direct assignments in place of all of the bindings, but this seems like it would cause a confusing widget API since I can't stop users from trying to use bindings which would confusingly get broken by the widget's black-box internal assignments...
Upvotes: 1
Views: 47
Reputation: 4208
You can temporarily override bindings using States, like in the code below.
The real problem here is detecting when the external value has changed, in my solution I'm using a Timer
for this, but your requirements ask for the external value to change again. Since you are externally binding to property text
and also overriding the binding to text
you temporarily loose the change signals from the external binding, hence cannot undo the temporary binding.
If you have control over the widget, I would implement a property which should be set externally and internally assign that value to where it should go. This gives you the ability to receive the changes and for example stop the tempBoundedTimer
(Since I still think you should have a timer to not indefinitely override the binding in case the external value fails to update).
If you don't have control over the widget, I would settly down on a suitable interval for tempBoundedTimer
(In any case, I don't adding a Timer in each instance of the widget is very nice)
import QtQuick 2.7
import QtQuick.Controls 2.0
ApplicationWindow {
visible: true
width: 640
height: 480
property real externalValue: (Math.random()* 50).toFixed(0)
Timer {
running: true
repeat: true
interval: 1000
onTriggered: {
// Simulate externalValue changes out of our control
externalValue = (Math.random()* 50).toFixed(0)
}
}
Component.onCompleted: {
// Unknown external binding set by developer using textItem widget
textItem.text = Qt.binding(function(){return externalValue})
}
Column {
Text {
id: textItem
text: ""
property real internalValue: (Math.random()* 50).toFixed(0)
Timer {
id: tempBoundedTimer
repeat: false
interval: 2000
}
states: [
State {
when: tempBoundedTimer.running
PropertyChanges {
target: textItem
text: "internal:" + internalValue
}
}
]
}
Button {
text: "Change Internal Value"
onClicked: {
textItem.internalValue = (Math.random()* 50).toFixed(0)
tempBoundedTimer.start()
}
}
}
}
BTW, I think your Binding object should actually also work if the when
is bound to tempBoundedTimer.running
, but I couldn't get it to play nice. It seems the Qt.binding
has priority
Upvotes: 1