Bert Becker
Bert Becker

Reputation: 41

How to modify the object of a javafx object property calling change listeners?

I have a javafx.beans.property.ObjectProperty<Calendar>. How can I modify the Calendar, so that javafx is registering it and the change listeners are invoked?

So, when I try to set the calendar field Calendar.YEAR is there a better solution than

Calendar c = duedateCalendar.get();
c.set(Calendar.YEAR,2017);
duedateCalendar.set(c);

Upvotes: 2

Views: 780

Answers (1)

James_D
James_D

Reputation: 209724

Setting a property value will be a no-op if the value you pass is equal to the current value, which in this case it clearly is:

Calendar c = duedateCalendar.get();
// c is now a copy of the reference held internally by duedateCalendar

c.set(Calendar.YEAR,2017);
// this updates the Calendar object referenced both by c and internally
// by duedateCalendar. Since the YEAR field in Calendar is just a primitive,
// and is not an observable value in the JavaFX sense, nothing is notified
// of the change

duedateCalendar.set(c);
// the value passed to set here is equal (indeed identical) to the value
// held internally by duedateCalendar (since it's an actual copy of the
// same reference). Internally, duedateCalendar will compare the parameter
// to the value it already holds, will see that they are the same, and
// so will take no action (including not notifying listeners)

Consequently no change events will be fired (nothing observable has actually changed).

You can create a new Calendar representing the new date and set it to that:

Calendar c = duedateCalendar.get();
Calendar newDueDate = Calendar.getInstance();
newDueDate.setTime(c.getTime());
newDueDate.set(Calendar.YEAR, 2017);
duedateCalendar.set(newDueDate);

As an aside, I strongly recommend using the java.time API (e.g. LocalDate or LocalDateTime) instead of the legacy Calendar class. Classes in this API are largely immutable (so they work better with the JavaFX property classes), and have functional methods that return new instances of the appropriate classes. For example, LocalDate is immutable and has methods such as LocalDate.plusYears(...) that return a reference to a new LocalDate object. So you can do:

// just create a random date sometime in 2016:
Random rng = new Random();
LocalDate random2016Date = LocalDate.of(2016, 1, 1).plusDays(rng.nextInt(365));

// general listener for logging:
ChangeListener<Object> listener = (obs, oldVal, newVal) -> System.out.println(oldVal + " -> " + newVal);


ObjectProperty<LocalDate> date = new SimpleObjectProperty<>(random2016Date);
date.addListener(listener);

// add one year to the current date:
date.set(date.get().plusYears(1));

Upvotes: 9

Related Questions