0

Consider the following models, Apple

public class Apple { private StringProperty appleName = new SimpleStringProperty("Apple"); public String getAppleName() { return appleName.get(); } public StringProperty appleNameProperty() { return appleName; } public void setAppleName(String appleName) { this.appleName.set(appleName); } } 

and Basket

public class Basket { private Apple apple = new Apple(); public Apple getApple() { return apple; } public void setApple(Apple apple) { this.apple = apple; } } 

Basket has an apple. Now I'm trying to bind a simple string property as below.

public class Food{ public static void main(String[] args) { StringProperty localApple = new SimpleStringProperty("lGreenApple"); Basket basket = new Basket(); Apple rGreenApple = new Apple(); rGreenApple.setAppleName("rGreenApple"); basket.setApple(rGreenApple); Bindings.bindBidirectional(localApple, rGreenApple.appleNameProperty()); rGreenApple.appleNameProperty().set("rGreenApple 2"); System.out.println(localApple.getValue()); //rGreenApple 2 Apple redApple = new Apple(); redApple.setAppleName("rRedApple"); basket.setApple(redApple); redApple.appleNameProperty().set("rRedApple 2"); System.out.println(localApple.getValue());//Still rGreenApple 2 } } 

While trying to retrieve value after binding, still localApple object has reference to rGreenApple. What is the clean way to get the red apple?

1 Answer 1

1

You need two things:

  1. Make the apple property in Basket a JavaFX observable property, instead of a regular JavaBean-style property.
  2. Bind the local string property to a "property of a property", i.e. the appleName property of the apple property of the Basket.

The first part is easy:

public class Basket { private final ObjectProperty<Apple> apple = new SimpleObjectProperty<>(); public ObjectProperty<Apple> appleProperty() { return apple ; } public final Apple getApple() { return appleProperty().get(); } public final void setApple(Apple apple) { appleProperty().set(apple); } } 

For the second part, the cleanest way is to use the EasyBind framework:

public class Food{ public static void main(String[] args) { Basket basket = new Basket(); Apple rGreenApple = new Apple(); rGreenApple.setAppleName("rGreenApple"); basket.setApple(rGreenApple); Property<String> localApple = EasyBind.monadic(basket.appleProperty()) .selectProperty(Apple::appleNameProperty); rGreenApple.appleNameProperty().set("rGreenApple 2"); System.out.println(localApple.getValue()); //rGreenApple 2 Apple redApple = new Apple(); redApple.setAppleName("rRedApple"); basket.setApple(redApple); System.out.println(localApple.getValue());// rRedApple redApple.appleNameProperty().set("rRedApple 2"); System.out.println(localApple.getValue());// rRedApple 2 } } 

Without EasyBind, you have to manage the intermediate listeners by hand. Something like:

 StringProperty localApple = new SimpleStringProperty(); localApple.bindBidirectional(basket.getApple().appleNameProperty()); basket.appleProperty().addListener((obs, oldApple, newApple) -> { if (oldApple != null) { localApple.unbindBidirectional(oldApple.appleNameProperty()); } if (newApple == null) { localApple.set(""); } else { localApple.bindBidirectional(newApple.appleNameProperty()); } }); 
Sign up to request clarification or add additional context in comments.

4 Comments

Can we do that without any new additional dependencies?
Not easily... You'd basically just end up replicating the relevant parts of the framework code.
Added a way to do this without EasyBind. If you have a longer chain of properties, it gets pretty ugly.
Tried both. Though it's EasyBind is nice, I'll go with listener for approach to know more. Much thanks.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.