Question

I have figured out how to filter by file-type, but I cannot figure out how to filter out files as I type on my keyboard in the file-name textfield. If I have 1000 files in my directory and two of them start with the letter q then I expect that when I type the word q in my JFileChooser it will filter out all files that do not start with q and this should continue as I type and the best possible match should be selected. Is there no exemplar for this? It seems like every JFileChooser question and tutorial out there is only concerned with filtering by file-type and not by name.

Was it helpful?

Solution

This works (for Metal LAF). Although it is a terrible solution in itself, the other options are not more appetizing.

public class FilterChooser {

    JFileChooser chooser = new JFileChooser();
    JTextField tf = (JTextField) ((JPanel) ((JPanel) chooser.getComponent(3)).getComponent(0)).getComponent(1);

    FilterChooser() {

        tf.getDocument().addDocumentListener(new DocumentListener() {

            public void insertUpdate(DocumentEvent e) {

                modifyFilter();
            }

            public void removeUpdate(DocumentEvent e) {

                modifyFilter();
            }

            public void changedUpdate(DocumentEvent e) {

                modifyFilter();
            }
        });

        JFrame f = new JFrame();
        chooser.showOpenDialog(f);

        f.setLocationRelativeTo(null);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack();
        f.setVisible(true);
    }

    void modifyFilter() {

        final String text = tf.getText();
        chooser.setFileFilter(new FileFilter() {

            @Override
            public String getDescription() {

                return null;
            }

            @Override
            public boolean accept(File f) {

                return (f.isDirectory() || f.getName().startsWith(text));
            }
        });
    }

    public static void main(String[] args) {

        new FilterChooser();
    }
}

Notes and explanations:

  • The text field in a JFileChooser is declared in the MetalFileChooserUI class as a private field, hence no easy way to reach it. I fetch it into tf the way I do because I did my homework and checked where it is located - if the layout changes (won't happen in the next many years due to backwards compatibility) this will break. You can alternatively recursively iterate through child components.
  • I set the filter for files only. If you want this to apply to directories, change the accept method of the FileFilter.
  • The filter is case-sensitive as it is currently implemented. You can modify this behavior by changing the accept method of the FileFilter.
  • I added the empty frame just so the JVM will exit when you close it (the file chooser, being a dialog, does not do this).
  • Depending on the bigger picture, set the modifiers of the fields and methods to your needs.

OTHER TIPS

I imagine that implementing a full-scale auto-complete for a JFileChooser might not be trivial. You would need access to the JTextField of the chooser, but that isn't readily available (though not impossible). You could then apply a custom DocumentFilter to that field, and then auto-populate (and partial select the back end of the word) as the user types.

Further reading: http://docs.oracle.com/javase/tutorial/uiswing/components/generaltext.html#filter

However, that seems like a lot of work.

Instead, are you aware that JFileChooser allows you to create a filter on-the-fly? Just bring up the chooser, type in 'q*', hit ENTER, and the chooser will show only the files that begin with 'q'.

I have the behavior that I want now. I still cannot believe what a struggle this was, but I guess nobody in the Swing community ever saw it fit to have the JFileChooser have this behavior or have better hooks for implementing it. Thank you user1803551 for your answer, I am accepting your answer and I posted mine just to show how I tweaked yours to get my exact desired behavior.

public void setupListeners()
{
    JFileChooser chooser = new JFileChooser();
    JTextField fileChooserTextField = (JTextField) ((JPanel) ((JPanel) chooser.getComponent(3)).getComponent(0)).getComponent(1);

    chooser.addKeyListener(new KeyListener()
    {
       @Override
       public void keyTyped(KeyEvent e)
       {
       }
       @Override
       public void keyReleased(KeyEvent e)
       {
          filterAsYouType(fileChooserTextField, chooser);
       }
       @Override
       public void keyPressed(KeyEvent e)
       {
       }
    });
}

    private void filterAsYouType(final JTextField tf, final JFileChooser chooser)
    {
    final String text = tf.getText();
    chooser.setFileFilter(new FileFilter()
    {
       @Override
       public boolean accept(File f)
       {
          if(text.equals("")
          {
             return true;
          }
          if(f.getName().equals(text))
          {
             chooser.setSelectedFile(f);
             tf.setCaretPosition(text.length());
          }
          if(f.getName().startsWith(text))
          {
             return true;
          }
          return false;
       }
       @Override
       public String getDescription()
       {
          return null;
       }
    });
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top