在使用swing的程序中經常用到JFileChooser,並且經常需要自定義一個FileFilter的子類來在文件列表中屏蔽不需要的文件。
大多數情況下,該子類是這樣設計的:
public ImgFileFilter
extends FileFilter{
public boolean accept(File f) {
if (f.isDirectory()) {
return true;
}
// Utils is a user custom utility class, getExtension
// is used to return the extension of a file.
String extension = Utils.getExtension(f);
if (extension != null) {
if (extension.equals(Utils.tiff) ||
extension.equals(Utils.tif) ||
extension.equals(Utils.gif) ||
extension.equals(Utils.jpeg) ||
extension.equals(Utils.jpg) ||
extension.equals(Utils.png)) {
return true;
} else {
return false;
}
}
return false;
}
public boolean getDescription(){
return "Image Files.";
}
}
這段代碼取自sun公司的"Java Tutorial". 正象你所看到的,accept(File file)方法決定一個文件是否顯示,如果返回值爲true,則顯示,反之,屏蔽。
麻煩的是如果你要使用多項文件類型選擇,比如在EditPluse裏,你可以選擇打開*.txt, *.cpp, *.java等文件。爲了這類需求,你不得不一個一個爲不同的文件選擇設計不同的FileFilter。有沒有更方便的方法來實現FileFilter呢?我設計了一個工具類可以解決這個問題,使用它,幾行代碼就可以完成一個JFileChooser的設計:
JFileChooser chooser = new JFileChooser();
FileFilterBuilder builder = FileFilterBuilder.newInstance().
chooser.setFileFilter(
builder.createFileFilter(
"*.tiff;*.tif;*.gif;*.jpeg;*.jpg;*.png"
,"Image Files(*.tiff;*.tif;*.gif;*.jpeg;*.jpg;*.png)"));
chooser.setFileFilter(
builder.createFileFilter(
"*.cpp;*.h",
"Cpp Files(*.cpp;*.h)"));
chooser.setFileFilter(
builder.createFileFilter( "exam*.cpp;exam?.h", "example Files(*.cpp;*.h)")); chooser.showOpenDialog(null); 僅僅是這幾行代碼就實現了第一個程序的功能,另外,還增加了一個選擇cpp文件的功能和一個選擇以exam開頭的cpp文件或以exam開頭的後跟一個字符的.h文件。下面,我將把我的設計介紹個大家。 從jsdk1.4開始,在java.util.regex出現了一個新的java類Pattern。Pattern是一個編譯了的正則表達式的。它有很強大的功能,在這裏我只使用其中一點點。在Pattern類中有一個方法matches(String regex, CharSequence input)可以判斷是否一個input可以與一個regex向符合。"regex"是"regular expression"的縮寫, 一個正則表達式是一個字符串模型, 和Windows中文件名模型一樣, 比如, "*.exe" 就是一個可以包括所有可執行文件的文件名模型。 到這裏,你會猜到我要做什麼了。首先,我介紹幾個程序中用到的regex的特徵。 在一個regex中,字符"."代表任何一個字符,".*"代表零個或多個字符,".{n}"代表n個任意字符。我們可以作一個測試。 import java.util.regex.Pattern; public class TestRegex { public static void main(String[] args) { String regex, input; regex = args[0]; input = args[1]; boolean isMatch = Pattern.matches(regex, input); System.out.println(isMatch); } } 上面代碼中,args[0]是一個你提供的regex,args[1]是一個待判定的字符串,如果該字符串與regex相符,程序將打印True,否則,false。通過提供不同的運行參數並查看運行結果,可以幫助你瞭解regex。 我們知道,在windows文件名模型中"?"代表一個字符,與regex中的".{1}"相對應;"*"代表0個或多個字符,與regex中的".*"相對應。如果一個字符串中包含"????",那麼,對應的,我們可以在regex中使用".{4}"與之匹配。最後一個重要的事情是對於字符".",regex應該使用"[.]"與之對應。 好了,事情結束了,正象你所猜測的,我的設計的核心是把windows的文件名模型轉換成regex,然後使用這個regex來決定那些文件可以顯示,那些文件不顯示。下面列出所有代碼。 /* * @(#)FileFilterBuilder.java 1.0 06/01/03 * @author Unagain */ package je14tut.dom; import java.io.File; import java.util.regex.Pattern; import javax.swing.filechooser.FileFilter; /** * The <code>FileFilterBuilder</code> class is a singleton, it can create * a appropriate <code>FilterFilter</code> object for a <code>JFileChooser</code> object * in your code, rather than to write a subclass of FileFilter manually. * <p> * You can use <code>newInstance</code> to obtain the only instance, and use * <code>createFileFilter</code> to get the <code>FileFilter</code>. * * @author Jason * */ public class FileFilterBuilder { static FileFilterBuilder INSTANCE; static final int NAME = 0; static final int EXT = 1; private FileFilterBuilder() {} /** * create and get the singleton instance. * @return FileterBuilder. */ public static FileFilterBuilder newInstance() { if (INSTANCE == null) { INSTANCE = new FileFilterBuilder(); } return INSTANCE; } /** * The only functional method in this class so far, used to create a appropriate * <code>FileFilter</code> instance you perferred based on a windows system file pattern * you given. * * @param winFilePattern - A window system file pattern, such as "*.java", "new*.*", * "ex?mp*.exe", etc. * <blockquote>you can specified two or more pattern once, split each other with ";", for example * "*.java;*.html", etc. </blockquote> * @param description * @return */ public FileFilter createFileFilter(String winFilePattern, final String description) { final String pattern = PatternBuilder.createFileRegex(winFilePattern); FileFilter filter = new FileFilter() { public boolean accept(File f) { if (f.isDirectory()) { return true; } return Pattern.matches(pattern, f.getName().toLowerCase()); } public String getDescription() { return description; } }; return filter; } } /** * <code>PatternBuilder</code> has only one methoes so far, it just as a translator to convert a * windows system file pattern to a java regular expression for <code>FileFilterBuiolder</code>. * In fact it is more power than FileFilter needed, for Considering possibly usage in future, I * separate it from <code>FileFilterBuiolder</code>. * @author Jason */ class PatternBuilder { private PatternBuilder() {} public static String createFileRegex(String filePattern) { StringBuffer regex = new StringBuffer(); boolean lastIsQueMark = false; int queMarkCount = 0; filePattern = filePattern.toLowerCase(); for (int i=0; i<filePattern.length(); i++) { char chr = filePattern.charAt(i); if (chr == '?') { if (!lastIsQueMark) { regex.append(".{"); lastIsQueMark = true; } queMarkCount ++; } else { if (lastIsQueMark) { regex.append(queMarkCount); regex.append("}"); queMarkCount = 0; lastIsQueMark = false; } switch(chr){ case '*': regex.append(".*"); break; case '.': regex.append("[.]"); break; case ';': regex.append("|"); break; default: regex.append(chr); } } } return regex.toString(); } }