JavaFX: Adding rows to TableView with a HashMap binding


Question

Suppose that I have a map collection:

ObserableHashMap<K,V> map = FXCollections.observableHashMap();

I put 1 record into this map during fxml controller initialization, then wrap it as ObservableList:

ObservableList<ObserableHashMap.Entry<K,V>> list = FXCollections.observableArrayList(map.entrySet());

then setitems for my tableView.setItems(list);

Everything is fine when I run this JavaFX app and 1 record is showing.

Question is that:

When I add more records later to my map, my TableView will not refresh these records.

How could I bind a dynamical map collection into my TableView?

Thanks

1
3
2/12/2014 11:28:22 PM

If you use an ObservableList of ObservableMaps as your TableView's data structure

ObservableList<ObservableMap> rowMaps = FXCollections.observableArrayList();
tableView.setItems(rowMaps);

and implement your own ObservableMapValueFactory

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.MapChangeListener;
import javafx.collections.ObservableMap;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellDataFeatures;
import javafx.util.Callback;

public class ObservableMapValueFactory<V> implements
        Callback<TableColumn.CellDataFeatures<ObservableMap, V>, ObservableValue<V>> {

    private final Object key;

    public ObservableMapValueFactory(Object key) {
        this.key = key;
    }

    @Override
    public ObservableValue<V> call(CellDataFeatures<ObservableMap, V> features) {
        final ObservableMap map = features.getValue();
        final ObjectProperty<V> property = new SimpleObjectProperty<V>((V) map.get(key));
        map.addListener(new MapChangeListener<Object, V>() {
            public void onChanged(Change<?, ? extends V> change) {
                if (key.equals(change.getKey())) {
                    property.set((V) map.get(key));
                }
            }
        });
        return property;
    }
}

and then set it as the cell value factory for your column(s)

column.setCellValueFactory(new ObservableMapValueFactory<String>(columnId));

all changes to your data are reflected in the TableView, even changes only affecting the ObservableMaps.

4
3/31/2014 9:27:55 PM

Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon