本身可观察的Javafx可观察值列表?

Javafx observable list of values that are themselves observable?

现在我有以下内容:

ObservableList<Person> personsList;

我用于显示人员列表的 UI 与 personsList 相关联。

人物如下:

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
}

问题是 SomeItem 是可变的,因此我希望将对 SomeItem 的任何更改传播到原始 personsList。

我怎样才能实现这样的目标??基于谷歌搜索,我做了以下修改,但我不确定它们是否有效!

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>
}

据我了解,当任何 ObservablePropertyBase 发生变化时,此更改将使 SomeItem 报告,然后 ObservableListValue 会将此更改向上传播,这将被 personsList 捕获?

编辑:问题 2: 是否可以强制刷新 personsList?假设我对特定的 SomeItem 进行了全面更新,然后我可以刷新整个 personsList?

您可以通过使用提取器创建 ObservableList 来触发 Change 事件。

这是一个例子:

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;
    }

}

一些Item.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();
    }

}

输出:

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]]]