javasearchjavafxfilefilter

JavaFX filter ListView File elements using FileFilter


I hava JavaFX application which shows all folders of a specific directory and watches for new/deleted folders and updates the ListView.

Now I'm trying to let the user filter/search the folders using a TextField.
I've done that before, so this is the relevant code:

@Override
public void initialize(URL location, ResourceBundle resources) {
    // configure other stuff
    configureListView();
}

private void configureListView() {
    searchField.textProperty().addListener((observable, oldVal, newVal) -> {
        handleSearchOnType(observable, oldVal, newVal);
    });
    // more stuff here
}

private void handleSearchOnType(ObservableValue observable, String oldVal, String newVal) {
    File folderToSearch = new File(config.getDlRootPath());
    ObservableList<File> filteredList = FXCollections.observableArrayList(folderToSearch.listFiles(
            pathname -> pathname.isDirectory() && pathname.getName().contains(newVal))); // something seems wrong here?!
    if (!searchField.getText().isEmpty()) {
        listView.setItems(filteredList);
    } else {
        // nothing to filter
        listView.setItems(FXCollections.observableArrayList(
            folderToSearch.listFiles(pathname -> pathname.isDirectory())));
        }
    }

This gives me strange results, e.g.:

no search search for 'test'

What am I missing here?

Thank you in advance!

Edit:

My custom cell factory

listView.setCellFactory(new Callback<ListView<File>, ListCell<File>>() {
            @Override
            public ListCell<File> call(ListView<File> list) {
                return new ListCell<File>() {
                    @Override
                    protected void updateItem(File t, boolean bln) {
                        super.updateItem(t, bln);
                        if (t != null) {
                            setGraphic(new ImageView(new Image("img/folder.png")));
                            setText(t.getName());
                        }
                    }

                };
            }
        });

Solution

  • Not sure if this is the only thing wrong, but your custom cell factory needs to handle the case where the cell is empty:

    final Image image = new Image("img/folder.png");
    
    listView.setCellFactory(new Callback<ListView<File>, ListCell<File>>() {
        @Override
        public ListCell<File> call(ListView<File> list) {
            return new ListCell<File>() {
                private final ImageView imageView = new ImageView(image);
                @Override
                protected void updateItem(File t, boolean bln) {
                    super.updateItem(t, bln);
                    if (t == null) {
                        setGraphic(null);
                        setText(null);
                    } else {
                        setGraphic(imageView);
                        setText(t.getName());
                    }
                }
    
            };
        }
    });
    

    The point here is that when you start filtering, some cells which previously were not empty will become empty. updateItem(null, true) will be invoked on those cells, which need to then clear all their content (otherwise they just keep the content they had before).

    (For a bonus, I also refactored slightly so that you don't keep loading the image from the image file in every cell, every time the user scrolls the list view.)