|
||||||||||
|
SummaryBy Jon Sharpe
JFileChooser
is a class supplied with Swing that lets users select specific files from mapped drives. It imitates the Windows Explorer and Unix File Manager programs. This Java tip shows you how to use it, and gives you details on some of the problems it can run into. (2,300 words)
Java Tips | |
---|---|
For a comprehensive list of Java Tips published in JavaWorld, see the Java Tips Index
Do you have a tip that would benefit JavaWorld's
readers? We would like to pass it on! Submit your tip to
javatips@javaworld.com.
|
JFileChooser
dialog class is one of the most useful classes
that Swing provides. It allows users to choose either a single
file or multiple files that match specified file filters. It
provides Java programs with a platform-independent GUI component
that does the same job as Internet Explorer under Microsoft Windows and
Unix's File Manager.
Imagine the following scenario: your user wishes to open a
specific file on a specific drive so that she can edit it using your text-editing
program. How do you help her do this? Windows and Unix
applications provide a file dialog box, allowing the user to
select the file she wishes to see. Wouldn't it be nice if the same capability existed in Java? Fortunately, there is JFileChooser
, a platform-independent version of this file dialog box
that provides this capability.
In this article, I'll show you how to use
JFileChooser
effectively, as well as help you avoid some of its pitfalls. I'll show you how to set filters so that your users
only see certain file types, how to set and handle the
directories, and how to determine which files the user has
selected.
|
A simple JFileChooser
Swing provides a free, platform-independent JFileChooser
class. To use it, all you need to do is instantiate it (as you
would with any other object) and show it to the user.
//for a default JFileChooser using the default directory
JFileChooser fc = new JFileChooser();
fc.showOpenDialog(parentComponent)
//where the 'parentComponent' is normally
//a JFrame or a JDialog.
Since I have not specified the directory that the JFileChooser
should use, it will use a default. Since there is no concept of a current directory in Java, JFileChooser
defaults to using
the user.dir
, which is defined in the system properties.
The JFileChooser
has six constructors. Three of these are of particular interest to us:
JFileChooser()
: Creates a JFileChooser
pointing to the user's home directory
JFileChooser(File currentDirectory)
: Creates a JFileChooser
using the given File
as the path
JFileChooser(String currentDirectoryPath)
: Creates a JFileChooser
using the given path
By using the last two constructors listed above, you can set the initial directory. The following examples demonstrate how to do this in a Windows environment:
//with the string representation of the path
JFileChooser fc = new JFileChooser("C:\\temp\\");
fc.showOpenDialog(parentComponent)
//using a file object as the directory rather than a String
File file = new File("C:\\temp\\");
JFileChooser fc = new JFileChooser(file);
fc.showOpenDialog(parentComponent)
Each of the examples above creates a JFileChooser
that
displays the contents of the default or specified directory to
the user. The filters (marked as such on the figure above) will default to All Files and *.*.
Handling the user's response
Displaying the JFileChooser
is all well and good, but as of yet we have no way to obtain the user's response. As it stands, any
choice the user makes will cause the JFileChooser
dialog to
disappear, without the program ever doing anything about the user's
actions.
Programs can determine which file the user selected in the following manner:
JFileChooser fc = new JFileChooser();
//the "this" in the below code is the JFrame that acts as the
//parent to the JFileChooser dialog.
int returnVal = fc.showOpenDialog(this);
//declare the file object
File selectedFile = null;
//OR handle multiple files with
// File[] selectedFiles;
//this accounts for multiple selected files.
//Query the JFileChooser to get the input from the user
if(returnVal == JFileChooser.APPROVE_OPTION)
{
selectedFile = fc.getSelectedFile();
// OR
// selectedFiles = fc.getSelectedFiles();
//to handle multiple returns.
}
The code fragment above allows the user to select a file, so that the underlying program can handle the selection in an appropriate manner (open it, delete it, copy it, and so forth).
It's that simple, at least for a simple JFileChooser
.
Tailoring the filters
Filters are a mechanism you can use to manipulate
what the user can select, and, more importantly, manipulate what
the user initially sees when first displaying JFileChooser
. The last thing a user wants to do is scroll up and down a
directory tree, hunting through every file in the system, looking for a specific file.
For example, if you are writing an HTML editor, then the user will initially want to see only files with .html
and .htm
extensions.
Later, when she wants to add a picture, she would only be interested in seeing image files (those with extensions like .gif
, .jpg
, .tiff
, and so on). Therefore, you would want to filter the files so that
only the image files are displayed to the user.
To implement a file filter, you have to write a class
that extends the FileFilter
class, which is an abstract class,
and implement the following methods:
boolean accept(java.io.File file)
String getDescription()
The accept
method is the engine of the FileFilter
class. The
JFileChooser
passes a file to the FileFilter
objects and asks the FileFilter
to determine whether or not it should be displayed to the user. The
FileFilter
code must answer the following questions:
getDescription
is the method that is used to populate
the description box of the file filters (as shown in the figure above). These two methods will then be used to tailor the JFileChooser
.
As an example, the HTMLFilter
subclass below displays only HTML
files:
import java.io.File;
/**
Class to filter files for .html and .htm only
@author Jon Sharpe
*/
public class HTMLFilter extends
javax.swing.filechooser.FileFilter
{
/**
This is the one of the methods that is declared in
the abstract class
*/
public boolean accept(File f)
{
//if it is a directory -- we want to show it so return true.
if (f.isDirectory())
return true;
//get the extension of the file
String extension = getExtension(f);
//check to see if the extension is equal to "html" or "htm"
if ((extension.equals("html")) || (extension.equals("htm")))
return true;
//default -- fall through. False is return on all
//occasions except:
//a) the file is a directory
//b) the file's extension is what we are looking for.
return false;
}
/**
Again, this is declared in the abstract class
The description of this filter
*/
public String getDescription()
{
return "HTML files";
}
/**
Method to get the extension of the file, in lowercase
*/
private String getExtension(File f)
{
String s = f.getName();
int i = s.lastIndexOf('.');
if (i > 0 && i < s.length() - 1)
return s.substring(i+1).toLowerCase();
return "";
}
}
Once you have created a filter, you can use it
on files. This is handled
internally by the JFileChooser
dialog, and all you have to do is apply the filter to the JFileChooser
class.
There are two ways of applying the filters to the JFileChooser
:
by setting or adding them.
Setting filters
Setting the filter overrides JFileChooser
's default action, which is *.*. Once you have set
the filters, the default will become whatever you have set it to,
rather than *.*.
//fc declared as above
fc.setFileFilter(new HTMLFilter());
Setting a filter will remove any filters that have been added or previously set.
Adding filters
When a filter is added to JFileChooser
, it is
appended to the list of filters already stored
internally. In my experience, the last file to be added or set is the one
that is first displayed to the user.
//fc declared as above
fc.addChoosableFileFilter(new HTMLFilter());
Fun and games
Swing has some problems and traps that
can catch unwary programmers, just as other parts of the JDK and the Java class
libraries do.
Java 1.1 has a reputation for behaving unexpectedly; for example, it has inconsistent naming strategies, in which methods do not behave the way their names
suggest. Most of these behavioral problems have been ironed out in Java 2, but
there are still some pitfalls you'll want to avoid.
The JFileChooser
is no exception; it has a couple traps that are absolute beauties. There are also ways that some thought can make coding and handling the JFileChooser
a lot easier.
The loading trap
One thing most people don't consider when they are creating, handling, and manipulating the JFileChooser
is its performance on multiple platforms.
I have an HTML tool that uses a JFileChooser
dialog to let
users select files. I initially had the
JFileChooser
create and populate itself when
the Open command was activated. I developed and tested the
code on a Windows 95 box, running JDK 1.3 beta, with four
mapped drives (a floppy drive, two 1 GB hard drives, and my
CD-ROM). It ran fine.
I then moved the code over to a Windows NT box, running JDK 1.2,
which has sixteen mapped drives, and it took nearly two minutes for the
JFileChooser
to appear.
The reason: the Windows NT machine has nearly 200 GB of
mapped drives, and the JFileChooser
runs through all of that storage space in order to
create its file map. Going through 200 GB takes time, especially when you're trying to do it over a slow network.
I had to find a way to hide the process of populating the
JFileChooser
from the user. My solution to the problem was to first make the JFileChooser fc
a class object. Therefore, I had
to create and populate it only once (so long as I did
not set it to null after I had finished). All I had to
do was alter and reset the filters on it to display different
file types.
Next, once the GUI HTML tool had finished loading and just
before the constructor terminated, I started a separate thread and
allowed the JFileChooser
to populate in the background. I also
disabled the Open menu item until after the JFileChooser
had finished loading.
There are, of course, tradeoffs that I made here:
JFileChooser
can be used.
JFileChooser
object to work with. This isn't
a major problem, but this object is always referenced, and it will
always be populated, taking up memory and space.
JFileChooser
.
The FileFilter trap
There are several problems with how the JFileChooser
handles
filters. These include:
I have noted these problems on Windows platforms, so it may be a Windows-specific problem, rather than one that occurs on all Java VMs.
FileFilters
Creating a file filter class can be somewhat of a pain, as
the vast majority of the code is purely replicated from any
other class that you use to filter files. So why not write a
generic class that can handle any type of file
extension and have any type of description associated with the files being filtered?
GenericFileFilter
, provided in the Resources section below, is such
a class. You construct it in the following way:
String fileExts = {"html","htm"};
//construct it giving it an array of file
//extensions and a description string
GenericFileFilter html =
new GenericFileFilter(fileExts, "HTML Files");
This is a lot simpler. You can then use the created file filter in the same way as any other file filter.
A few general issues
The following is a list of general issues that are worth
noting when using a JFileChooser
.
user.dir
, which is picked up
from the system properties.
JFileChooser
.
JFileChooser
has the method getFileFilters
, which returns an array of file filters, it does not have the methods setFileFilters(FileFilter[] in)
or
addChoosableFileFilters(FileFilter[] in)
. Again, this is somewhat illogical.
Conclusion
JFileChooser
is a simple and clean class that you can
use to add an effective touch to your
application. Because it is a Swing component, the actual look and feel
will vary from platform to platform, leading
users to believe that they are using a native tool rather than
cross-platform Java.
JFileChooser
does have some features that make it illogical and tricky to program, as well as difficult for
the user to understand. However, careful programming and a
small amount of thought can bypass most of the problems.
About the author
Jon Sharpe has a BS in applied chemistry and a MS in parallel computer systems. He has been programming in Java for more than three years, and Swing for nearly eighteen months. Currently, he is working in London as a Java programmer for a UK bank. In his spare time, he enjoys writing Java code, as well as acting and singing in a local amateur drama group in west London. |
|
(c) Copyright ITworld.com, Inc., an IDG Communications company
GenericFileFilter
:
JFileChooser
: