Search code examples
javafxsettableviewjavafx-8

How use Set as base for TableView


I have developed some code and I have a Set of Users:

public class ParkCentral{
    private Set<User> users = new HashSet<>();
}

Then, in a different class, I'm developing a GUI and a TableView of Users. The problem is that I can't create a ObervableList from a Set. And I would like that changes on ParkCentral.users would be reflected on TableView.

It is possible do this without changing ParkCentral implementation, without changing the Set to List?

Why TableView only works with ObservableList and not with ObservableSet or ObservableMap?


Solution

  • Why TableView only works with ObservableList and not with ObservableSet or ObservableMap?

    A TableView presents an ordered collection of items. Neither Map nor Set fulfill those requirements (except for some implementations).

    It's possible to listen to changes in the Set and make appropriate changes in the List though. This is not possible with just a HashSet though; there's simply no way to observe this collection; you'd always need to manually update the list after changes have been made.

    Using a ObservableSet instead allows you to add a listener that does updates to a list though.

    public class SetContentBinding<T> {
    
        private final ObservableSet<T> source;
        private final Collection<? super T> target;
        private final SetChangeListener<T> listener;
    
        public SetContentBinding(ObservableSet<T> source, Collection<? super T> target) {
            if (source == null || target == null) {
                throw new IllegalArgumentException();
            }
            this.source = source;
            this.target = target;
            target.clear();
            target.addAll(source);
            this.listener = c -> {
                if (c.wasAdded()) {
                    target.add(c.getElementAdded());
                } else {
                    target.remove(c.getElementRemoved());
                }
            };
            source.addListener(this.listener);
        }
    
        /**
         * dispose the binding
         */
        public void unbind() {
            source.removeListener(listener);
        }
    
    }
    

    Usage example:

    public class ParkCentral{
        private ObservableSet<User> users = FXCollections.observableSet(new HashSet<>());
    }
    
    new SetContentBinding(parkCentral.getUsers(), tableView.getItems());