Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to bind a ObservableList to a ObservableMap?

I get data in the format of an ObservableMap<T, Foo>. To implement this data in a View I need the values of that map in the format of an ObservableList<Foo>.

Because I need the data in a Map Collection (to avoid duplicates and other reasons) I was wondering if it is possible to bind these 2 collections.

Something like:

ObservableMap<Integer, Foo> data = FXCollections.observableHashMap();
ObservableList<Foo> target = FXCollections.observableArrayList();

// Won't work 
Bindings.bindContent(target, data.values());

Binding because the data can change during runtime.

Edit: Initializing the List with map values is not working because the there will be addtional Foo's added to the map: Example with a String as map value:

ObservableMap<Integer, String> map = FXCollections.observableHashMap();
map.put(1, "a");
map.put(2, "b");

ObservableList<String> list = FXCollections.observableArrayList(map.value());

//map = {1=a, 2=b}
//list = [a, b]
// ok

map.put(3, "c");

//map = {1=a, 2=b, 3=c}
//list = [a, b]
// no update    
like image 352
Thomas Bernhard Avatar asked Aug 20 '19 11:08

Thomas Bernhard


2 Answers

from ObservableMap to ObservableList

ObservableMap<Integer, Foo> data = FXCollections.observableHashMap();
ObservableList<Foo> target = FXCollections.observableArrayList(data.values());
like image 97
rohit prakash Avatar answered Nov 01 '22 11:11

rohit prakash


I have not found a built in solution in Java. I use a simple MapChangeListener when the Map is the source of the data, and the List is only for tracking changes to the Map value list.

    ObservableMap<String, String> map = FXCollections.observableHashMap();
    ObservableList<String> list = FXCollections.observableArrayList();

    MapChangeListener<String, String> listener = c -> {
        if (c.wasRemoved()) {
            list.remove(c.getValueRemoved());
        }

        if (c.wasAdded()) {
            list.add(c.getValueAdded());
        }
    };

    map.addListener(listener);

    map.put("1", "A");
    map.put("2", "B");
    map.put("1", "A'");

    assertThat(list).containsExactlyInAnyOrder("A'", "B");

You should keep the observable list private, and only expose a unmodifiableObservableList externally, to prevent accidently adding list entries that are not in the map.

like image 41
NaderNader Avatar answered Nov 01 '22 11:11

NaderNader