javalistlistviewjavafxfiltered

Filtering ListView with multiple controls JavaFX


I am developing a project which has a pane to create an Event(Meeting) in my program.

This pane has a ListView of Rooms which needs to constantly be updated using a list of available filters in the interface (TextView's, CheckBox's, DateTimePicker, Spinner), for example if I write "1" in the name textview and set capacity to 10 it is supposed to apply that 2 filters to the listview and only show the rooms which name contains "1" and capacity=10.

Here is a picture of my pane. enter image description here

What I have done is adding a listener to each of the control's text or value property, but the problem is when I apply more than 1 filter it doesn't apply the 2 filters together, and I will need to apply multiple.

This is the code I've done for 2 of the filters, but like I said I will need more.

    listRooms = new ListView<>();
    FilteredList<Room> filteredList= new FilteredList<>(roomsList, data -> true);

    
    txtRoomName.textProperty().addListener(obs->{
        String filter = txtRoomName.getText();
        if(filter == null || filter.length() == 0) {
            filteredList.setPredicate(s -> true);
        }
        else {
            filteredList.setPredicate(s -> s.getName().contains(filter));
        }
    });

    spCapacity.valueProperty().addListener(obs->{
        int filter = spCapacity.getValue();
        if(filter == 0) {
            filteredList.setPredicate(s -> true);
        }
        else {
            filteredList.setPredicate(s -> s.getCapacity() == filter);
        }
    });

Solution

  • Make a method to generate the predicate. Collect ALL of the filter criteria there, regardless of which one changed:

    txtRoomName.textProperty().addListener(obs->{
        calculatePredicate();
    });
    spCapacity.valueProperty().addListener(obs->{
        calculatePredicate();
    });
    
    private void calculatePredicate() {
        String filterTxt = txtRoomName.getText();
        int filterCap = spCapacity.getValue();
    
        filteredList.setPredicate(s -> {
            boolean txtMatch = filterTxt == null || filterTxt.isEmpty() || s.getName().contains(filterTxt);
            boolean capMatch = filterCap == 0 || s.getCapacity() == filterCap;
            return txtMatch && capMatch;
        });
    }