Java JFileChooser在键入时按名称筛选文件

Java JFileChooser在键入时按名称筛选文件,java,swing,user-interface,filter,jfilechooser,Java,Swing,User Interface,Filter,Jfilechooser,我已经知道了如何按文件类型过滤,但当我在键盘上的文件名文本字段中键入时,我无法知道如何过滤文件。如果我的目录中有1000个文件,其中两个文件以字母q开头,那么我希望当我在myJFileChooser中键入单词q时,它会过滤掉所有不以q开头的文件,并且在我键入时应继续此操作,并应选择最佳匹配项。没有这方面的范例吗?似乎每个JFileChooser问题和教程都只关注按文件类型过滤,而不是按名称过滤。我认为为JFileChooser实现全面自动完成可能不是一件小事。您需要访问选择器的JTextFiel

我已经知道了如何按文件类型过滤,但当我在键盘上的文件名文本字段中键入时,我无法知道如何过滤文件。如果我的目录中有1000个文件,其中两个文件以字母q开头,那么我希望当我在my
JFileChooser
中键入单词q时,它会过滤掉所有不以q开头的文件,并且在我键入时应继续此操作,并应选择最佳匹配项。没有这方面的范例吗?似乎每个
JFileChooser
问题和教程都只关注按文件类型过滤,而不是按名称过滤。

我认为为
JFileChooser
实现全面自动完成可能不是一件小事。您需要访问选择器的JTextField,但这并不容易(尽管并非不可能)。然后,您可以对该字段应用自定义DocumentFilter,然后根据用户类型自动填充(并部分选择单词的后端)

进一步阅读:

然而,这似乎需要做很多工作

相反,您是否知道JFileChooser允许您动态创建过滤器?只需调出选择器,输入
'q*”
,点击回车键,选择器将只显示以“q”开头的文件。

这适用于金属LAF。虽然这本身就是一个糟糕的解决方案,但其他的选择并不是很诱人

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();
    }
}
注释和解释:

  • JFileChooser中的文本字段在
    MetalFileChooserUI
    类中声明为
    private
    字段,因此无法轻松访问它。我把它放到
    tf
    中,因为我做了家庭作业并检查了它的位置——如果布局发生变化(由于向后兼容,在未来许多年内不会发生),这将中断。您也可以递归地遍历子组件
  • 我只为文件设置了过滤器。如果要将此应用于目录,请更改
    FileFilter
    accept
    方法
  • 筛选器区分大小写,因为它当前已实现。您可以通过更改
    FileFilter
    accept
    方法来修改此行为
  • 我添加了空帧,以便JVM在您关闭它时退出(作为对话框的文件选择器不会这样做)
  • 根据大图,根据需要设置字段和方法的修饰符

    • 我现在有了我想要的行为。我仍然无法相信这是一场多么艰难的斗争,但我想Swing社区中没有人认为让JFileChooser拥有这种行为或者有更好的钩子来实现它是合适的。感谢用户1803551的回答,我接受了你的回答,我发布了我的答案,只是为了展示我如何调整你的答案,以获得我想要的行为

      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;
             }
          });
          }
      }
      

      类似于?这篇文章来自2001年,声称在1.4中JFileChooser有一个内置的提前类型选择器。我没能找到这个。我对这篇文章也有很多问题。首先,“findJList”方法很粗糙。其次,没有完整的代码示例。第三点也是最后一点,当您键入时从视图中筛选出文件的行为没有得到解决。在现代Java中,必须有一种更优雅的方式来实现这种行为。您是否知道,如果您选择一个文件并键入一个字母序列,它会为您导航到以该序列开头的文件?您要修改的文本字段是
      MetalFileChooserUI
      中的
      私有
      字段(假设为Metal-LAF)。这里没有太多选项-从UI类复制粘贴代码或遍历文件选择器。您刚才用*描述的行为非常有效。我想让这种行为在每次击键时都发生,而不仅仅限于添加*和按enter键。可能吗?我对全尺寸自动完成不感兴趣。我想在键入时进行筛选。
      我对全刻度自动完成不感兴趣。我想在键入时进行筛选。
      我看不出有什么区别。你能解释一下吗?我想在键入时进行筛选自动完成对我来说,但这些功能在默认情况下使用startWith,而不是contains,不可能是,我认为没有问题,但正如@splungebob所描述的那样并不容易,而且在我键入时需要effortBy过滤器。我的意思是,如果我在下面的JTextField中点击“f”,那么上面JList中的所有文件都应该消失,除非它们以“f”开头。我不希望JTextField自动完成以“f”开头的第一个文件,这是自动完成。我的意思清楚了吗?这很有效!但是我有一个问题,如果我点击一个文件,然后在一个目录上远离它,然后再次点击该文件,文件选择器中的选择就会消失。我不明白为什么会发生这种事……嗯。。。对第一次选择文件时也会发生这种情况。发生的情况是,无论何时更改过滤器,文件和文件夹列表都会刷新,并且您将丢失当前选择。它实际上也发生在你打字的时候,但在这种情况下你不会注意到它。如果您愿意,可以使选择文件不会自动将其名称放入字段。设置新过滤器后,我们尝试重新选择文件,列表会刷新,但这并不容易。由于某种原因,
      invokeLater
      无法在此处执行此任务。我们可以采取一些不顾一切的措施,你认为呢?既然你在
      KeyListener
      中只实现了一个方法,你最好使用
      KeyAdapter
      。此外,不确定为什么需要检查文本是否等于“”,空字符串会自动工作;您在第二个
      if
      中缺少了一个
      返回true
      。此外,我认为需要将KeyListener添加到JTextField,而不是选择器