I need to implement file browsing feature in my app and while I am aware of possibility of making a JList item and doing it manually I had an idea to just implement JFileChooser for this. I managed to reduce the JFileChooser just to list of directories and files but I wasn't able to override some of it's functionalities. I have been going through source code but no luck. My idea is for it to handle as following: On the top of the list to have a /... directory so when clicked on it it returns to parent folder. Also when double clicked on directory it sets it as current directory. When double clicked on file it returns the file as selected.
This is the code I used so far:
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);
I tried adding custom MouseListener to the JFileChooser but it didn't work.
This is the result I have so far:
![](https://www.manongdao.com/static/images/pcload.jpg)
Any idea which classes or listeners to overwrite/replace so I can achieve 2 desired effects?
This is what I am looking for in visual terms:
![](https://www.manongdao.com/static/images/pcload.jpg)
On the top of the list to have a /... directory so when clicked on i
it returns to parent folder.
JFileChooser
has method with name changeToParentDirectory()
. So you could simply add a Button and call that method.
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.
You can set a PropertyChangeListener
to listen for JFileChooser.DIRECTORY_CHANGED_PROPERTY
property that is fired whenever the current directory has changed using double click or the internal commands.
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.
You can set an ActionListener
to listen for JFileChooser.APPROVE_SELECTION
action that is fired whenever a file is chosen by double click.
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());
}
}
});
EDIT:
you misunderstood me for the parent folder action. Here is an image
to describe it.
This could be achieved by using a manipulated FileSystemView
with the JFileChooser
that is responsible for interacting with the content of the filesystem. My implementation manipulates the getFiles
method to smuggle a special File
in the list that has a defined name and points to the parent directory.
I'm not quite sure if this is a very good idea, since this is really not meant to be in the JFileChooser
Code but here we go.
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();
}
});
EDIT2:
is there a quick solution to set scroll from horizontal to vertical
for JFileChooser?
There are two possibilities. The simple one is to change the style of your JFileChooser
to the Details View
by adding this code:
Action details = fc.getActionMap().get("viewTypeDetails");
details.actionPerformed(null);
The more complex one is to change the LayoutOrientation
of the file view JList
that is a component of sun.swing.FilePane
that is the Component
with ID:2
in the JFileChooser
.
One problem here is that FilePane
is not part of the Java Library but part of the Core Library and not accessible by default. But you can use Reflection to get the field private JList list;
in the FilePane
and change its LayoutOrientation
to JList.VERTICAL
with this code:
// 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);