重新利用 JFileChooser

Repurposing JFileChooser

我需要在我的应用程序中实现文件浏览功能,虽然我知道制作 JList 项目并手动执行它的可能性,但我有一个想法为此实现 JFileChooser。我设法将 JFileChooser 缩减为目录和文件列表,但我无法覆盖它的某些功能。我一直在浏览源代码,但没有运气。我的想法是按如下方式处理:在列表的顶部有一个 /... 目录,因此当单击它时它 returns 到父文件夹。此外,当双击目录时,它会将其设置为当前目录。当双击文件时,它 returns 文件被选中。

这是我目前使用的代码:

final JFileChooser fc = new JFileChooser();
fc.setControlButtonsAreShown(false);
fc.setCurrentDirectory(paths[list.getSelectedIndex()]);
/*remove unwanted components*/
for(int i = 0; i < fc.getComponentCount(); i++) {
    fc.getComponent(0).setVisible(false);
    fc.getComponent(1).setVisible(false);
    fc.getComponent(3).setVisible(false);
}
add(fc, BorderLayout.CENTER);

我尝试将自定义 MouseListener 添加到 JFileChooser,但没有成功。

这是我目前的结果:

知道 类 或听众 overwrite/replace 可以达到 2 个预期效果吗?

这就是我在视觉方面寻找的东西:

On the top of the list to have a /... directory so when clicked on i it returns to parent folder.

JFileChooser 有名称为 changeToParentDirectory() 的方法。所以您可以简单地添加一个 Button 并调用该方法。

JButton toParent = new JButton("/..");
toParent.addActionListener(new ActionListener(){
    @Override
    public void actionPerformed(ActionEvent a) {
        fc.changeToParentDirectory();
    }
});
fc.add(toParent, BorderLayout.NORTH);

Also when double clicked on directory it sets it as current directory.

您可以设置一个 PropertyChangeListener 来侦听 JFileChooser.DIRECTORY_CHANGED_PROPERTY 属性,当使用双击或内部命令更改当前目录时触发。

fc.addPropertyChangeListener(new PropertyChangeListener(){
    @Override
    public void propertyChange(PropertyChangeEvent e) {
        String command = e.getPropertyName();
        if (command.equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY)) {
            File currentDir = fc.getCurrentDirectory();
            System.out.println(currentDir.getAbsolutePath());
        }
    }   
});

When double clicked on file it returns the file as selected.

您可以设置 ActionListener 来侦听 JFileChooser.APPROVE_SELECTION 每当双击选择文件时触发的操作。

fc.addActionListener(new ActionListener(){
    @Override
    public void actionPerformed(ActionEvent e) {
        String command = e.getActionCommand();
        if (command.equals(JFileChooser.APPROVE_SELECTION)) {
            File selectedFile = fc.getSelectedFile();
            System.out.println(selectedFile.getAbsolutePath());
        }   
    }   
});


编辑:

you misunderstood me for the parent folder action. Here is an image to describe it.

这可以通过使用一个被操纵的 FileSystemView 和负责与文件系统内容交互的 JFileChooser 来实现。我的实现操纵 getFiles 方法在列表中走私一个特殊的 File,它具有已定义的名称并指向父目录。
我不太确定这是否是个好主意,因为这真的不应该出现在 JFileChooser 代码中,但我们开始吧。

fc.setFileSystemView(new FileSystemView(){
    // this method is abstract but since you don't
    // want to create directories here you don't 
    // need to implement it.
    @Override
    public File createNewFolder(File f) throws IOException {
        return null;
    }

    // manipulate the default getFiles method that creates
    // the list of files in the current directory
    @Override
    public File[] getFiles(File dir, boolean useFileHiding){
        // get the list of files from default implementation
        File[] files = super.getFiles(dir,useFileHiding);
        // get the parent directory of current
        File parent = getParentDirectory(dir);
        // skip the next for problematic folders with
        // empty names and root folders
        if(!dir.getName().isEmpty() && !isRoot(dir)){
            // create a new list of files with one extra place
            File[] nfiles = new File[files.length + 1];
            // add a special file to list that points to parent directory
            nfiles[0] = new File(parent.getAbsolutePath()){
                // set a special name for that file
                @Override
                    public String getName(){return "...";}
                };
            // add the rest of files to list
            for(int i = 0; i < files.length; i++)
                nfiles[i+1] = files[i];
            // use the new list
            files = nfiles; 
        }
        // return list of files
        return files;
    }

    // some special folders like "c:" gets converted
    // in shellfolders.Then our setted name "..." would
    // get converted to "local drive (c:)". This garantees
    // that our setted name will be used.
    @Override
    public String getSystemDisplayName(File f) {
        return f.getName();
    }   
});

编辑 2:

is there a quick solution to set scroll from horizontal to vertical for JFileChooser?

有两种可能。最简单的方法是通过添加以下代码将 JFileChooser 的样式更改为 Details View

Action details = fc.getActionMap().get("viewTypeDetails");
details.actionPerformed(null);

更复杂的是更改文件视图 JListLayoutOrientation,它是 sun.swing.FilePane 的一个组件,即 ComponentID:2JFileChooser.
这里的一个问题是 FilePane 不是 Java 库的一部分,而是核心库的一部分,默认情况下不可访问。但是您可以使用反射获取 FilePane 中的字段 private JList list; 并使用以下代码将其 LayoutOrientation 更改为 JList.VERTICAL

// get the FilePane Component of JFileChooser
Object filepane = fc.getComponent(2);
// get the list field with reflection
Field field_list = filepane.getClass().getDeclaredField("list");
// get access to this private field
field_list.setAccessible(true);
// read the value of the field
JList<?> list = (JList<?>)field_list.get(filepane);
// change the layout orientation
list.setLayoutOrientation(JList.VERTICAL);