Search code examples
javajavafxjavafx-8observable

JavaFX observableList as a value in a Map


So I am trying to create an ObservableMap that has String as a key and FXCollections.observableList as a value

    Map<String, ObservableList<String>> namesMap = new HashMap<>();
    ObservableMap<String, ObservableList<String>> names = FXCollections.observableMap(namesMap);
    names.addListener(new MapChangeListener<String, List<String>>() {
        @Override
        public void onChanged(MapChangeListener.Change<? extends String, ? extends List<String>> change) {
            System.out.println("Detected a change!");
            System.out.println(change.getValueAdded());
        }
    });

    names.put("1", FXCollections.observableArrayList().addListener(new ListChangeListener<String>(){
        @Override
        public void onChanged(ListChangeListener.Change<? extends String> c) {
            //to-do
        }

    }));
    names.get("1").add("One");

But it gives me this error at the line where I'm assigning listener to the value of the key 1. I put FXCollections.observableArrayList() as a value for the key 1 because when creating an observable list, that is the value that is assigned so I tried to set that as a value. Suggestions of the compiler didn't help. The reason why I am doing this is to create an observable map with values that I could track/observe if a change has happened.

Can anyone help me? Any help would be appreciated. Thanks!


Solution

  • The method ObservableList.addListener returns nothing (i.e. void). This means you are calling names.put("1", void) which is not valid.

    You need to create the ObservableList and add the listener separately.

    ObservableList<String> list = FXCollections.observableArrayList();
    list.addListener(/* your listener */);
    names.put("1", list);
    
    // OR
    
    // Less efficient since you have to perform a lookup
    // in order to add the listener.
    names.put("1", FXCollections.observableArrayList());
    names.get("1").addListener(/* your listener */);
    

    The other option is to add the ListChangeListener inside the MapChangeListener.

    // Stored in variable so it can be removed if necessary
    final ListChangeListener<String> listListener = listChange -> {
        // TODO: Implement...
    };
    names.addListener((MapChangeListener<String, ObservableList<String>>) mapChange -> {
        if (mapChange.wasAdded()) {
            mapChange.getValueAdded().addListener(listListener);
        } 
        if (mapChange.wasRemoved()) {
            mapChange.getValueRemoved().removeListener(listListener);
        }
    });
    
    // ListChangeListener will now be added automatically by the MapChangeListener
    names.put("1", FXCollections.observableArrayList());