Search code examples
listviewjavafx

JavaFX - Remove selected Items in a ListView


I have a ListView with Strings. I am using SceneBuilder and FXML @FXML private ListView<String> listView;

How can I delete all the selected Items in that ListView? SelectionMode.MULTIPLE is already set. listView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);

I tried it with listView.getSelectionModel().getSelectedItems() The issue here is that it will delete also not selected duplicate values in that list.

I know that there is also getSelectedIndices but i could not figure out how to properly use it :(


Solution

  • For each of the selected indices, remove the corresponding items from the backing list for the ListView.

    import javafx.application.Application;
    import javafx.collections.FXCollections;
    import javafx.geometry.Insets;
    import javafx.scene.Scene;
    import javafx.scene.control.*;
    import javafx.scene.layout.VBox;
    import javafx.stage.Stage;
    
    import java.io.IOException;
    
    public class ListApp extends Application {
        @Override
        public void start(Stage stage) throws IOException {
            ListView<String> listView = new ListView<>(
                    FXCollections.observableArrayList(
                            "apple", "apple", "pear", "peach"
                    )
            );
            listView.getSelectionModel().setSelectionMode(
                    SelectionMode.MULTIPLE
            );
    
            Button removeSelected = new Button("Remove selected");
            removeSelected.setOnAction(e -> {
                ObservableList<Integer> indices =
                    listView.getSelectionModel().getSelectedIndices().sorted();
    
                for (int k = indices.size() - 1; k >= 0; k--) {
                    listView.getItems().remove(
                            (int) indices.get(k)
                    );
                }
            });
    
            VBox layout = new VBox(10, removeSelected, listView);
            layout.setPadding(new Insets(10));
    
            stage.setScene(new Scene(layout));
            stage.show();
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    

    For large lists, it will be more efficient to remove using an iterator, or even replacing the existing list with a new one, but for small lists the implementation above should be fine.


    One might think that the following would work, but it won't, at least in this case where the objects in the list aren't guaranteed to be unique:

    listView.getItems().removeAll(
        listView.getSelectionModel().getSelectedItems()
    );
    

    The underlying type for the ListView in this case is String. Eventually removeAll will invoke remove on the underlying collection, which:

    removes an element e such that Objects.equals(o, e), if this collection contains one or more such elements

    So, if there are multiple strings with the same value, it will remove the unselected ones with the selected ones.

    If instead, you remove by selected index, then only the elements in the list that are actually selected will be removed.