Set a new JFileChooser FileFilter and reset previous ones

2.4k views Asked by At

I want a file filter with 2 options, one to show all files and the other to show a specific extension.

The specific extension should be the one selected by default.

I'm using the same JFileChooser twice, the first time to show .fas files, and the second to show .xls files.

Right now I'm using this code, but for some reasons it does not overwrite previous file extensions. Many answers here on SO have similar code and exactly the same problem, if you recycle your JFileChooser.

First portion, everything works

fileChooser.setFileFilter(new javax.swing.filechooser.FileFilter() {
    @Override
    public boolean accept(File file) {
        return file.isDirectory() || file.getAbsolutePath().endsWith(".fas");
    }

    @Override
    public String getDescription() {
        return "Fasta";
    }
});
// more modern API, same result
// fileChooser.setFileFilter(new FileNameExtensionFilter("File fasta", "fas"));

Second portion. This is used in a second "opening" of the same JFileChooser. It seems like it just adds a filter (the option to select .fas files remains).

// delete name of previously selected file
File currentDirectory = fileChooser.getCurrentDirectory();
fileChooser.setSelectedFile(new File(""));
fileChooser.setCurrentDirectory(currentDirectory);

// set new file filter
fileChooser.setFileFilter(new javax.swing.filechooser.FileFilter() {
    @Override
    public boolean accept(File file) {
        return file.isDirectory() || file.getAbsolutePath().endsWith(".xls");
    }

    @Override
    public String getDescription() {
        return "Excel 97";
    }
});
// more modern API, same result
// fileChooser.setFileFilter(new FileNameExtensionFilter("Excel 97", "xls"));

2

There are 2 answers

3
Agostino On BEST ANSWER

I guess the name setFileFilter can be misleading, because what it does in reality is set the selected file filter (without replacing the other filters).

If you want to recycle your JFileChooser, the simplest solution is to make a call to resetChoosableFileFilters() before setting the new filters.

Code for the first selection

fileChooser.setFileFilter(new FileNameExtensionFilter("File fasta", "fas"));

Code for the second selection

// delete name of previously selected file, but stay in the same directory
File currentDirectory = fileChooser.getCurrentDirectory();
fileChooser.setSelectedFile(new File(""));
fileChooser.setCurrentDirectory(currentDirectory);

// reset current file filters
fileChooser.resetChoosableFileFilters();

// set new file filter
fileChooser.setFileFilter(new FileNameExtensionFilter("Excel 97", "xls"));

// the "All files" filter will be present too, unless you uncomment this
// fileChooser.setAcceptAllFileFilterUsed(false);
10
Thomas On

Try using the xxxChoosableFileFilter() methods which seem to be the ones driving the combobox model.

setFileFilter() seems to set the basic filter that is used for the combobox if there are no choosable filters. However, if there are choosable filters the basic filter would be ignored. So I assume that somewhere in the code (yours or Swing) the basic filter is added to the choosables.

Here's a snippet of JDK 8 source for one of the combobox models which seems to do what I mentioned above:

public Object getSelectedItem() {
  // Ensure that the current filter is in the list.
  // NOTE: we shouldnt' have to do this, since JFileChooser adds
  // the filter to the choosable filters list when the filter
  // is set. Lets be paranoid just in case someone overrides
  // setFileFilter in JFileChooser.
  FileFilter currentFilter = getFileChooser().getFileFilter();
  boolean found = false;
  if(currentFilter != null) {
    for (FileFilter filter : filters) {
      if (filter == currentFilter) {
         found = true;
      }
    }
    if(found == false) {
      getFileChooser().addChoosableFileFilter(currentFilter);
    }
  }
  return getFileChooser().getFileFilter();
}

As you can see the problem is that if the current filter is not part of the model's filters array, it is added to the choosable filters and thus keeps being displayed.