【问题标题】:JFileChooser filtering files by name as you typeJFileChooser 在您键入时按名称过滤文件
【发布时间】:2014-06-22 07:27:12
【问题描述】:

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

【问题讨论】:

  • 类似this?
  • 那篇文章来自 2001 年,声称在 1.4 中 JFileChooser 有一个内置的预先输入选择器。我一直没能找到这个。我对这篇文章也有多个问题。首先,“findJList”方法很老套。其次,没有完整的代码示例。第三也是最后一点,没有解决在您键入时从视图中过滤掉文件的行为。在现代 Java 中必须有一种更优雅的方式来实现这种行为。
  • 您是否知道,如果您选择一个文件并键入一系列字母,它会为您导航到以该序列开头的文件?
  • 您要修改的文本字段是MetalFileChooserUI 内的private 字段(假设金属LAF)。您在这里没有太多选择 - 从 UI 类复制粘贴代码或遍历文件选择器。

标签: java swing user-interface filter jfilechooser


【解决方案1】:

我想为JFileChooser 实现全面的自动完成可能并非易事。您需要访问选择器的 JTextField,但这并不容易获得(尽管并非不可能)。然后,您可以将自定义 DocumentFilter 应用于该字段,然后在用户键入时自动填充(并部分选择单词的后端)。

进一步阅读: http://docs.oracle.com/javase/tutorial/uiswing/components/generaltext.html#filter

但是,这似乎需要做很多工作。

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

【讨论】:

  • 您刚才用 * 描述的行为效果很好。我想让每次击键都会发生这种行为,而不仅限于添加 * 并按 Enter 键。那可能吗?我对全面的自动完成不感兴趣。我想在输入时进行过滤。
  • I am not interested in a full scale auto-complete. I want to filter as I type. 我看不出有什么区别。你能解释一下吗?
  • 我想在输入时进行过滤。 == 对我来说自动完成,但这些功能默认使用 startWith,不包含,不可能,我认为没有问题,但正如@splungebob 所描述的那样不容易并且需要努力
  • 输入过滤器是指如果我在下面的 JTextField 中点击“f”,那么上面的 JList 中的所有文件都应该消失,除非它们以“f”开头。我不希望 JTextField 自动完成以“f”开头的第一个文件,即自动完成。我的意思清楚了吗?
【解决方案2】:

这有效(用于金属 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,因为我做了功课并检查了它的位置 - 如果布局发生变化(由于向后兼容性在未来几年内不会发生),这 休息。您也可以递归地遍历子组件。
  • 我只为文件设置了过滤器。如果您希望将其应用于目录,请更改 FileFilteraccept 方法。
  • 过滤器在当前实施时区分大小写。您可以通过更改FileFilteraccept 方法来修改此行为。
  • 我添加了空框架,以便 JVM 在您关闭它时退出(文件选择器,作为一个对话框,不这样做)。
  • 根据大局,根据需要设置字段和方法的修饰符。

【讨论】:

  • 这行得通!但是我有一个问题,如果我单击一个文件,然后在目录上单击它,然后再次单击该文件,fileChooser 中的选择就会消失。我很困惑为什么会这样……
  • 嗯...是的。第一次选择文件时也会发生这种情况。发生的情况是,每当更改过滤器时,文件和文件夹列表都会刷新,并且您会丢失当前选择。它实际上也会在您键入时发生,但在这种情况下您不会注意到它。如果您愿意,可以使选择文件不会自动将其名称放入字段中。
  • 我尝试在设置新过滤器并刷新列表后重新选择文件,但这并不容易。出于某种原因,invokeLater 无法在这里完成工作。有绝望的措施可以采取,你怎么看?
【解决方案3】:

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

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

【讨论】:

  • 由于您在KeyListener 中只实现了一种方法,因此您最好使用KeyAdapter。另外,不知道为什么需要检查文本是否等于“”,空字符串会自动工作;您在第二个if 中缺少return true
  • 另外,我认为需要将KeyListener添加到JTextField,而不是Chooser
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-06
  • 2011-01-27
  • 1970-01-01
  • 2020-03-25
  • 2018-11-20
  • 2013-10-18
相关资源
最近更新 更多