Search code examples
listviewjavafxpropertieschangelistener

FX assessing if ListView is empty using different change listeners


I want to assess whether a ListView is empty to disable or enable a submit button. So in essence, when the ListView has no content the button is disabled and when it has 1 or more elements it is enabled.

I've managed to achieve this using a ListChangeListener, using code such as:

vp.addListChangeListener(change -> {
        change.next(); 

        if (change.getList().size() == 0 && change.wasRemoved() || change.getList().size() == 1 && change.wasAdded()) {
            bp.toggleSubmitAvailability("submit");
        }
    });

where the method addListChangeListener is as follows:

public void addListChangeListener(ListChangeListener<Name> listener) {
    names.addListener(listener);
}

What I ideally wanted to do was just use a traditional ChangeListener and listen to one of the properties associated with the ListView. As an example, I thought this may work:

vp.addItemsListener((observable, oldValue, newValue) -> {

        if (newValue.size() == 0 && oldValue.size() > 0 || newValue.size() == 1 && oldValue.size() == 0) {
            bp.toggleSubmitAvailability("submit");
        }
    });

where the method addItemsListener is as follows (and attaches a listener to the itemsProperty):

public void addItemsListener(ChangeListener<ObservableList<Name>> listener) {
        listView.itemsProperty().addListener(listener);
    }

However, for some reason, when I add items to my ListView, or well add items to the ObservableList that is attached to it, this property is not being changed, as nothing is happening - so what actually triggers the itemsProperty of the ListView to change, and if this approach will not work, is there a way to do what I did with the ListChangeListener by utilising another property associated with the ListView (in a reasonably elegant way of course)?


Solution

  • The itemsProperty() is the property that holds the list itself; listeners registered with it will get notified if you call listView.setItems(...), (i.e. if the list reference itself is changed) but will not get notified if you modify the content of the list it contains (i.e. if you do listView.getItems().add(...)).

    The Bindings class provides an isEmpty(ObservableList) method you can use here:

    button.disableProperty().bind(Bindings.isEmpty(listView.getItems()));
    

    or equivalently, with a listener:

    Bindings.isEmpty(listView.getItems()).addListener(
        (obs, wasEmpty, isNowEmpty) -> button.setDisable(isNowEmpty));
    

    So you could implement a method like this:

    public void addEmptyListListener(ChangeListener<Boolean> listener) {
        Bindings.isEmpty(listView.getItems()).addListener(listener);
    }
    

    and then do

    vp.addEmptyListListener((obs, wasEmpty, isNowEmpty) -> {
        // ...
    });