A long-term problem (some call it - maybe - a function :) is the weakness of all listeners set by all fx bindings. As a result, we cannot build “chains” of properties without maintaining a strong link to each link in the chain.
The specific type of such a chain link is JavaBeanProperty: its purpose is to adapt the javabean property to the fx property. As a rule, no one is interested in the adapter as such, so using it will do something like
private Parent createContentBean() {
...
Property property = createJavaBeanProperty();
Bindings.bindBidirectional(label.textProperty(), property, NumberFormat.getInstance());
.. wonders why the tag is not updating. Changing the property to a strong link will work as expected (leaving me puzzeld as to who is responsible for submitting the dummy, but this is another question):
Property property;
private Parent createContentBean() {
...
property = createJavaBeanProperty();
Bindings.bindBidirectional(label.textProperty(), property, NumberFormat.getInstance());
A long introduction, but almost there: jdk8 somehow changed the implementation, so the first approach now works, there is no longer any need to maintain a strong reference to JavaBeanProperty. Custom chain links, on the other hand, still need a strong link.
Questions:
- Is this a deliberate change in behavior, and if so, why?
- How is this achieved? The code looks very similar ... and I would like to try something like this in user adapters.
Full example game with:
public class BeanAdapterExample extends Application {
private Counter counter;
public BeanAdapterExample() {
this.counter = new Counter();
}
Property property;
private Parent createContentBean() {
VBox content = new VBox();
Label label = new Label();
property = createJavaBeanProperty();
Property property = createJavaBeanProperty();
Bindings.bindBidirectional(label.textProperty(), property, NumberFormat.getInstance());
Slider slider = new Slider();
slider.valueProperty().bindBidirectional(property);
Button button = new Button("increase");
button.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent paramT) {
counter.increase();
}
});
content.getChildren().add(label);
content.getChildren().add(slider);
content.getChildren().add(button);
return content;
}
protected JavaBeanDoubleProperty createJavaBeanProperty(){
try {
return JavaBeanDoublePropertyBuilder.create()
.bean(counter).name("count").build();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return null;
}
@Override
public void start(Stage stage) throws Exception {
Scene scene = new Scene(createContentBean());
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
public static class Counter {
private double count;
public Counter() {
this(0);
}
public Counter(double count) {
this.count = count;
}
public void increase() {
setCount(getCount()+ 1.);
}
public double getCount() {
return count;
}
public void setCount(double count) {
double old = getCount();
this.count = count;
firePropertyChange("count", old, getCount());
}
PropertyChangeSupport support = new PropertyChangeSupport(this);
public void addPropertyChangeListener(PropertyChangeListener l) {
support.addPropertyChangeListener(l);
}
public void removePropertyChangeListener(PropertyChangeListener l) {
support.removePropertyChangeListener(l);
}
protected void firePropertyChange(String name, Object oldValue,
Object newValue) {
support.firePropertyChange(name, oldValue, newValue);
}
}
}
BTW: Swing, beans