Issue
right now I have the following:
ObservableList<Person> personsList;
and my UI for displaying the person list is tied to personsList.
Person is something like below:
class Person {
Name name
// other details
List<SomeItem> list;
}
// Item is immutable, but SomeItem can mutate by setting and getting the Items
class SomeItem {
Item item
Item item2
}
The issue is SomeItem is mutable, so I would want any changes to SomeItem be propagated to the original personsList.
How would I achieve something like that?? Based on googling I kind of have the following modifications, but I am not sure if they work!
class Person {
Name name
// other details
List<SomeItem> list; // <-- change to ObservableListValue<SomeItem>
}
// Item is immutable, but SomeItem can mutate by setting and getting the Items
class SomeItem {
Item item // <-- change to ObservablePropertyBase<Item>
Item item2 // <-- change to ObservablePropertyBase<Item>
}
From what I understand, this changes would make SomeItem report when any ObservablePropertyBase<Item> changes, and then ObservableListValue<SomeItem> would propagate this changes up, which would be caught by personsList?
Edit: Question 2: Is it possible to force refresh personsList? Lets say I make an overall update to a specific SomeItem, then I can refresh the entire personsList?
Solution
You can fire Change
events by creating an ObservableList
with an extractor.
Here is an example:
Name.java:
public class Name {
private final String name;
public Name(String name) {
this.name = name;
}
public final String getName() {
return name;
}
}
Item.java:
public class Item {
private final String name;
public Item(String name) {
this.name = name;
}
public final String getName() {
return name;
}
@Override
public String toString() {
return name;
}
}
SomeItem.java:
public class SomeItem {
private final ObjectProperty<Item> item1 = new SimpleObjectProperty<>(this, "item1");
private final ObjectProperty<Item> item2 = new SimpleObjectProperty<>(this, "item2");
public SomeItem(Item item1, Item item2) {
this.item1.set(item1);
this.item2.set(item2);
}
public final ObjectProperty<Item> item1Property() {
return item1;
}
public final Item getItem1() {
return item1.get();
}
public final void setItem1(Item item) {
item1.set(item);
}
public final ObjectProperty<Item> item2Property() {
return item2;
}
public final Item getItem2() {
return item2.get();
}
public final void setItem2(Item item) {
item2.set(item);
}
@Override
public String toString() {
return "[" + item1.get() + ", " + item2.get() + "]";
}
}
Person.java:
public class Person {
private final Name name;
private final ObservableList<SomeItem> someItems = FXCollections.observableArrayList(someItem ->
new Observable[]{someItem.item1Property(), someItem.item2Property()});
public Person(Name name, SomeItem... someItems) {
this.name = name;
this.someItems.addAll(someItems);
}
public final Name getName() {
return name;
}
public final ObservableList<SomeItem> getSomeItems() {
return someItems;
}
@Override
public String toString() {
return "[name=" + name.getName() + ", someItems=" + someItems + "]";
}
}
App.java:
public class App extends Application {
@Override
public void start(Stage stage) {
SomeItem someItem1 = new SomeItem(new Item("item1"), new Item("item2"));
SomeItem someItem2 = new SomeItem(new Item("item3"), new Item("item4"));
SomeItem someItem3 = new SomeItem(new Item("item5"), new Item("item6"));
SomeItem someItem4 = new SomeItem(new Item("item7"), new Item("item8"));
Person person1 = new Person(new Name("person1"), someItem1, someItem2);
Person person2 = new Person(new Name("person2"), someItem3, someItem4);
ObservableList<Person> persons = FXCollections.observableArrayList(person ->
new Observable[]{person.someItemsProperty()});
persons.addAll(person1, person2);
persons.addListener((ListChangeListener<Person>) c -> {
while (c.next()) {
if (c.wasUpdated()) {
System.out.println("Updated persons:");
IntStream.range(c.getFrom(), c.getTo())
.mapToObj(index -> "Person at index " + index + " was updated to: " + c.getList().get(index))
.forEach(System.out::println);
}
}
});
// Update items to trigger change event for testing
someItem1.setItem1(new Item("item1Updated"));
someItem4.setItem2(new Item("item8Updated"));
}
public static void main(String[] args) {
launch();
}
}
Output:
Updated persons:
Person at index 0 was updated to: [name=person1, someItems=[[item1Updated, item2], [item3, item4]]]
Updated persons:
Person at index 1 was updated to: [name=person2, someItems=[[item5, item6], [item7, item8Updated]]]
Answered By - Oboe