The following properties can be used with either the long or contextual binding syntax
Bindings are usually setup in one direction. If this property is specified with a value of true
then a bidirectional binding will be created instead.import groovy.beans.Bindable
import groovy.swing.SwingBuilderclass MyModel {
@Bindable String value
}def model = new MyModel()
def swing = new SwingBuilder()
swing.edt {
frame(title: 'Binding', pack: true, visible: true) {
gridLayout(cols: 2, rows: 3)
label 'Normal'
textField(columns: 20, text: bind('value', target: model))
label 'Bidirectional'
textField(columns: 20, text: bind('value', target: model, mutual: true))
label 'Model'
textField(columns: 20, text: bind('value', source: model))
}
}
Typing text on textfield #2 pushes the value to model, which in turns updates textfield #2 and #3, demonstrating that textfield #2 listens top model updates. Typing text on textfield #2 pushes the value to textfield #3 but not #1, demonstrating that textfield #1 is not a bidirectional binding.
Transforms the value before it is sent to event listeners.import groovy.beans.Bindable
import groovy.swing.SwingBuilderclass MyModel {
@Bindable String value
}def convertValue = { val ->
'*' * val?.size()
}def model = new MyModel()
def swing = new SwingBuilder()
swing.edt {
frame(title: 'Binding', pack: true, visible: true) {
gridLayout(cols: 2, rows: 3)
label 'Normal'
textField(columns: 20, text: bind('value', target: model))
label 'Converter'
textField(columns: 20, text: bind('value', target: model, converter: convertValue))
label 'Model'
textField(columns: 20, text: bind('value', source: model))
}
}
Typing text on textfield #1 pushes the value to the model as expected, which you can inspect by looking at textfield #3. Typing text on textfield #2 however transform's every keystroke into an '*' character.
Guards the trigger. Prevents the event from being sent if the return value is false
or null
.import groovy.beans.Bindable
import groovy.swing.SwingBuilderclass MyModel {
@Bindable String value
}def isNumber = { val ->
if(!val) return true
try {
Double.parseDouble(val)
} catch(NumberFormatException e) {
false
}
}def model = new MyModel()
def swing = new SwingBuilder()
swing.edt {
frame(title: 'Binding', pack: true, visible: true) {
gridLayout(cols: 2, rows: 3)
label 'Normal'
textField(columns: 20, text: bind('value', target: model))
label 'Converter'
textField(columns: 20, text: bind('value', target: model, validator: isNumber))
label 'Model'
textField(columns: 20, text: bind('value', source: model))
}
}
You can type any characters on textfield #1 and see the result in textfield #3. You can only type numbers on textfield #2 and see the result in textfield #3
This type of validation is not suitable for semantic validation (a.k.a. constraints in domain classes). You would want to have a look at the Validation plugin.
Maps a different event type, instead of PropertyChangeEvent
.
Specify a value that may come from a different source. Usually found in partnership with sourceevent
.import groovy.beans.Bindable
import groovy.swing.SwingBuilderclass MyModel {
@Bindable String value
}def model = new MyModel()
def swing = new SwingBuilder()
swing.edt {
frame(title: 'Binding', pack: true, visible: true) {
gridLayout(cols: 2, rows: 3)
label 'Text'
textField(columns: 20, id: 'tf1')
label 'Trigger'
button('Copy Text', id: 'bt1')
bind(source: bt1,
sourceEvent: 'actionPerformed',
sourceValue: {tf1.text},
target: model,
targetProperty: 'value')
label 'Model'
textField(columns: 20, text: bind('value', source: model))
}
}
A contrived way to copy text from one textfield to another. The copy is performed by listening to ActionEvent
s pumped by the button.