Binding to a POJO
From Planet JFX
Contents |
[edit] Introduction
At this time, JavaFX variables bound to a pure-Java object (POJO) will not automatically update as they should. This article describes one or more ways to get two-way binding working.
[edit] Problem Statement
I want to get a JFX button to change state given a property change in Java code. I can pass the new state into the script but the binding does not work.
[edit] Solution using a PropertyChangeListener
There is a lot of code involved in solving this problem. Let's use PropertyChangeEvents since they map pretty well to what we need to get the interaction working.
[edit] Java
package test;
// import statements
...
public class NameKeeper {
// instance variables:
private String nameVar;
// property change listener methods:
// note: you can delegate the implementations
// of these methods to a PropertyChangeSupport...
public void addPropertyChangeListener(PropertyChangeListener list) ...
public void removePropertyChangeListener(PropertyChangeListener list) ...
private void fireEvent(PropertyChangeEvent e) ...
// property methods:
public String getName() ...
public void setName(String name) {
fireEvent(new PropertyChangeEvent(this, "name", nameVar, name));
nameVar = name;
}
}
[edit] JavaFX
import test.NameKeeper as JavaNameKeeper;
// above can't be the same name as a JFX class.
import java.beans.*;
class NameKeeper {
attribute name:String;
private attribute backer:JavaNameKeeper;
private attribute listener:PropertyChangeListener;
private attribute suppressCascade:Boolean;
}
// we want just one listener created, no matter how many different backers we use:
trigger on new NameKeeper {
var self = this;
this.listener = new PropertyChangeListener {
operation property Change(evt:PropertyChangeEvent) {
var propertyName = evt.getPropertyName();
println("NK.fx: got vetoChange: model:{self.backer} chg: '{propertyName}' from '{evt.getOldValue().toString()}' to 'evt.getNewValue().toString()}'");
if (propertyName == "name") {
self.suppressCascade = true;
self.name = (String)evt.getNewValue();
self.suppressCascade = false;
} // endif
} // endop
};
}
trigger on NameKeeper.name = newValue {
// only update backer if we are not updating in response to backer already...
if (not suppressCascade) {
backer.setName(newValue);
} // endif
}
trigger on NameKeeper.backer[oldValue] = newValue {
println("NK.fx: Setting model from '{oldValue}' to '{newValue}'");
// remove change listener from old:
if (oldValue <> null) {
oldValue.removePropertyChangeListener(listener);
} // end if
// check new for null:
if (newValue <> null) {
// we have a model, add change listener to new, rebuild:
newValue.addPropertyChangeListener(listener);
// capture the backer's name:
name = backer.getName();
} else {
// no backing object, clear out:
name = null;
} // end if
}
