第16章 選取器
本章介紹兩個Swing選取器元件,它們是:JFileChooser和JColorChooser,它們分别用于選取檔案和顔色。
16.1 JFileChooser
檔案選取器(與選項窗格一樣,參見14.3節“JOptionPane”)是放置在對話框中的輕量元件。一旦建立了一個JFileChooser執行個體,就可以把這個執行個體添加到一個對話框中。而且,JFileChooser類還提供了一些方法,這些方法把已存在的檔案添加到一個模态對話框中。并且顯示這個對話框。這些方法傳回一個integer值,指出是激活了選取器的準許按鈕還是清除了這個對話框。
檔案選取器支援三種顯示模式:隻顯示檔案、隻顯示目錄和顯示檔案及目錄。另外,檔案選取器還支援單檔案選取和多檔案選取(Swing1.1FCS不完全支援多檔案選取。)
可以用許多不同的方法來定制檔案選取器,如圖16-1所示。圖16-1中的上圖顯示調用JFileChooser.showSaveDialog()後顯示的标準對話框。圖16-1
例子 16-1 一個簡單的檔案選取器例子
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import javax.swing.*;
import javax.swing.filechooser.*;
import java.beans.*;
public class Test extends JFrame {
JFileChooser chooser = new JFileChooser();
JButton button = new JButton("show file chooser ...");
public Test() {
super("Simple File Chooser Application");
Container contentPane = getContentPane();
contentPane.setLayout(new FlowLayout());
contentPane.add(button);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int state = chooser.showOpenDialog(null);
File file = chooser.getSelectedFile();
if(file != null &&
state == JFileChooser.APPROVE_OPTION) {
JOptionPane.showMessageDialog(
null, file.getPath());
}
else if(state == JFileChooser.CANCEL_OPTION) {
null, "Canceled");
else if(state == JFileChooser.ERROR_OPTION) {
null, "Error!");
});
public static void main(String args[]) {
JFrame f = new Test();
f.setBounds(300,300,350,100);
f.setVisible(true);
f.setDefaultCloseOperation(
WindowConstants.DISPOSE_ON_CLOSE);
f.addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e) {
System.exit(0);
16.1.1 檔案選取器類型
例子 16-2 預設的檔案選取器類型
JComboBox comboBox = new JComboBox();
super("Standard File Chooser Types");
contentPane.add(comboBox);
comboBox.addItem("OPEN_DIALOG");
comboBox.addItem("SAVE_DIALOG");
comboBox.addItem("custom dialog");
String message = "CANCELED";
int state = showChooser(
(String)comboBox.getSelectedItem());
message = chooser.getApproveButtonText() +
" " + file.getPath();
JOptionPane.showMessageDialog(null, message);
private int showChooser(String s) {
int state;
if(s.equals("OPEN_DIALOG")) {
state = chooser.showOpenDialog(null);
else if(s.equals("SAVE_DIALOG")) {
state = chooser.showSaveDialog(null);
else { // custom dialog
String string = JOptionPane.showInputDialog(
null,
"Button/Title String:");
chooser.setApproveButtonMnemonic(string.charAt(1));
state = chooser.showDialog(Test.this, string);
return state;
16.1.2 可通路元件
例子 16-3 一個圖像預覽器可通路元件
import java.io.*;
ImagePreviewer previewer = new ImagePreviewer();
super("Accessory Components");
JButton button = new JButton("Select A File");
setAccessoryComponent();
chooser.showOpenDialog(null);
private void setAccessoryComponent() {
JPanel previewPanel = new JPanel();
previewPanel.setLayout(new BorderLayout());
previewPanel.add(new JLabel("Image Previewer",
SwingConstants.CENTER),
BorderLayout.NORTH);
previewPanel.add(previewer, BorderLayout.CENTER);
previewer.setPreferredSize(new Dimension(200,0));
previewer.setBorder(BorderFactory.createEtchedBorder());
chooser.setAccessory(previewPanel);
new ImagePreviewerAccessoryAdapter(chooser, previewer);
public static void main(String a[]) {
f.setBounds(300, 300, 300, 75);
class ImagePreviewerAccessoryAdapter extends Object {
public ImagePreviewerAccessoryAdapter(
JFileChooser chooser,
final ImagePreviewer previewer) {
chooser.addPropertyChangeListener(
new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent e) {
if(e.getPropertyName().equals(
JFileChooser.SELECTED_FILE_CHANGED_PROPERTY)) {
previewer.update((File)e.getNewValue());
class ImagePreviewer extends JComponent {
private ImageIcon icon;
public void update(File file) {
Dimension size = getSize();
Insets insets = getInsets();
icon = new ImageIcon(file.getPath());
icon.setImage(icon.getImage().getScaledInstance(
size.width - insets.left - insets.right,
size.height - insets.top - insets.bottom,
Image.SCALE_SMOOTH));
if(isShowing()) {
repaint();
public void paintComponent(Graphics g) {
super.paintComponent(g);
if(icon != null)
icon.paintIcon(this, g, insets.left, insets.top);
16.1.3 過濾檔案類型
例子 16-4 一個文本檔案過濾器和預覽器
import java.util.*;
import java.net.*;
TextPreviewer previewer = new TextPreviewer();
JPanel previewPanel = new PreviewPanel();
class PreviewPanel extends JPanel {
public PreviewPanel() {
JLabel label = new JLabel("Text Previewer",
SwingConstants.CENTER);
setPreferredSize(new Dimension(250,0));
setBorder(BorderFactory.createEtchedBorder());
setLayout(new BorderLayout());
label.setBorder(BorderFactory.createEtchedBorder());
add(label, BorderLayout.NORTH);
add(previewer, BorderLayout.CENTER);
JFileChooser.SELECTED_FILE_CHANGED_PROPERTY))
class TextPreviewer extends JComponent {
private JTextArea textArea = new JTextArea();
public TextPreviewer() {
add(new JScrollPane(textArea), BorderLayout.CENTER);
textArea.setText(contentsOfFile(file));
textArea.revalidate();
static String contentsOfFile(File file) {
String s = new String();
char[] buff = new char[50000];
InputStream is;
InputStreamReader reader;
URL url;
try {
reader = new FileReader(file);
int nch;
while ((
nch = reader.read(buff, 0, buff.length)) != -1) {
s = s + new String(buff, 0, nch);
catch (java.io.IOException ex) {
s = "Could not load file";
return s;
例子 16-5 多種檔案過濾器
import java.net.URL;
PreviewPanel previewPanel = new PreviewPanel();
setPreferredSize(new Dimension(350,0));
super("Filtering Files");
String s = "CANCELED";
if(state == JFileChooser.APPROVE_OPTION) {
s = "File Selected: " +
chooser.getSelectedFile().getPath();
JOptionPane.showMessageDialog(null, s);
chooser.addChoosableFileFilter(new TextFilter());
chooser.addChoosableFileFilter(new JavaCodeFilter());
previewer.configure((File)e.getNewValue());
abstract class SuffixAwareFilter
extends javax.swing.filechooser.FileFilter {
public String getSuffix(File f) {
String s = f.getPath(), suffix = null;
int i = s.lastIndexOf('.');
if(i > 0 && i < s.length() - 1)
suffix = s.substring(i+1).toLowerCase();
return suffix;
public boolean accept(File f) {
return f.isDirectory();
class ImageFilter extends SuffixAwareFilter {
boolean accept = super.accept(f);
if( ! accept) {
String suffix = getSuffix(f);
if(suffix != null)
accept = super.accept(f) || suffix.equals("jpg")
|| suffix.equals("gif");
return accept;
public String getDescription() {
return "Java Source Code Files(*.java)";
class JavaCodeFilter extends SuffixAwareFilter {
accept = super.accept(f) || suffix.equals("java");
class TextFilter extends SuffixAwareFilter {
return super.accept(f) || suffix.equals("txt");
return false;
return "Text Files(*.txt)";
private JScrollPane scrollPane = new JScrollPane(textArea);
textArea.setEditable(false);
add(scrollPane, BorderLayout.CENTER);
public void configure(File file) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JViewport vp = scrollPane.getViewport();
vp.setViewPosition(new Point(0,0));
16.1.4 檔案視圖
例子 16-6 一個定制的檔案視圖
import javax.swing.filechooser.FileView;
super("Custom File View Example");
chooser.setFileView(new CustomFileView());
int state = chooser.showSaveDialog(null);
if(state == JFileChooser.APPROVE_OPTION)
s = "File: " + file.getPath();
class CustomFileView extends FileView {
private Icon fileIcon = new ImageIcon("file.gif"),
directoryIcon = new ImageIcon("folder.gif"),
imageIcon = new ImageIcon("photo.jpg");
public String getName(File f) { return null; }
public String getDescription(File f) { return null; }
public String getTypeDescription(File f) { return null; }
public Icon getIcon(File f) {
Icon icon = null;
if(isImage(f)) icon = imageIcon;
else if(f.isDirectory()) icon = directoryIcon;
else icon = fileIcon;
return icon;
public Boolean isTraversable(File f) {
Boolean b = null;
if(f.getPath().equals("D://file.txt")) {
b = new Boolean(false);
else if(f.getPath().equals("D://books")) {
return b == null ? new Boolean(true) : b;
private boolean isImage(File f) {
boolean isImage = false;
if(suffix != null) {
isImage = suffix.equals("gif") ||
suffix.equals("bmp") ||
suffix.equals("jpg");
return isImage;
private String getSuffix(File file) {
String filestr = file.getPath(), suffix = null;
int i = filestr.lastIndexOf('.');
if(i > 0 && i < filestr.length()) {
suffix = filestr.substring(i+1).toLowerCase();
16.1.5 多檔案選取
例子 16-7 檔案選取器的多檔案選取
chooser.setMultiSelectionEnabled(true);
File[] files = chooser.getSelectedFiles();
String[] filenames = getFilenames(files);
if(filenames != null &&
JOptionPane.showMessageDialog(null,filenames);
private String[] getFilenames(File[] files) {
String[] filenames = null;
int numFiles = files.length;
System.out.println(numFiles);
if(files.length > 0) {
filenames = new String[numFiles];
for(int i=0; i < numFiles; ++i) {
filenames[i] = files[i].getPath();
System.out.println(filenames[i]);
return filenames;
16.1.6 JFileChooser屬性
16.1.7 JFileChooser事件
例子 16-8 JFileChooser動作事件
JDialog dialog;
String title = chooser.getDialogTitle();
if(title == null)
chooser.getUI().getDialogTitle(chooser);
dialog = new JDialog((Frame)null, title, false);
Container dialogContentPane =
dialog.getContentPane();
dialogContentPane.setLayout(new BorderLayout());
dialogContentPane.add(chooser,
BorderLayout.CENTER);
dialog.setTitle("Non-Modal File Chooser");
dialog.pack();
dialog.setLocationRelativeTo(Test.this);
dialog.setVisible(true);
chooser.addActionListener(new ActionListener() {
String state = (String)e.getActionCommand();
if(state.equals(JFileChooser.APPROVE_SELECTION)) {
else if(
state.equals(JFileChooser.CANCEL_SELECTION)) {
// JFileChooser action listeners are notified
// when one either the approve button or
// cancel button is activated
dialog.setVisible(false);
16.1.8 JFileChooser類總結
16.1.9 AWT相容
16.2 JColorChooser
例16-9 在一個小應用程式中顯示的顔色選取器
import javax.swing.colorchooser.*;
import javax.swing.event.*;
public class Test extends JApplet {
JColorChooser chooser = new JColorChooser();
ColorSelectionModel model = chooser.getSelectionModel();
public void init() {
getContentPane().add(chooser, BorderLayout.CENTER);
model.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
showStatus("Color: " + chooser.getColor());
16.2.1 在對話框中顯示顔色選取器
例16-10 在對話框中顯示的顔色選取器
getContentPane().add(new Palette(), BorderLayout.CENTER);
class Palette extends JPanel {
private Color[] defaultColors = new Color[] {
Color.blue, Color.red, Color.yellow, Color.green,
Color.magenta, Color.darkGray, Color.white, Color.orange,
Color.pink, Color.cyan, Color.lightGray, Color.gray,
};
public Palette() {
int columns = 3;
setBorder(
BorderFactory.createTitledBorder("Color Palette"));
setLayout(new GridLayout(columns,0,1,1));
for(int i=0; i < defaultColors.length; ++i)
add(new ColorPatch(defaultColors[i]));
class ColorPatch extends JPanel {
JApplet applet;
Color selectedColor;
public ColorPatch(Color color) {
setBackground(color);
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
selectedColor = JColorChooser.showDialog(
ColorPatch.this, // parent comp
"Pick A Color", // dialog title
getBackground()); // initial color
if(selectedColor == null) {
JOptionPane.showMessageDialog(ColorPatch.this,
"ColorChooser Canceled");
else {
setBackground(selectedColor);
"Color Selected: " + selectedColor);
16.2.2 定制顔色選取器
例16-11 顔色選取器中的一個定制預覽
private JColorChooser chooser = new JColorChooser();
private JButton button = new JButton("Show Color Chooser");
private JDialog dialog;
contentPane.add(button, BorderLayout.CENTER);
chooser.setPreviewPanel(new PreviewPanel());
if(dialog == null)
dialog = JColorChooser.createDialog(
Test.this, // parent comp
false, // modality
chooser,
null, null);
setPreferredSize(new Dimension(0,100));
setBorder(BorderFactory.createRaisedBevelBorder());
g.setColor(getForeground());
g.fillRect(0,0,size.width,size.height);
例16-12 實作一個定制顔色選取器面闆
private AbstractColorChooserPanel colorPanels[] =
new AbstractColorChooserPanel[] {
new ListPanel(),
chooser.setChooserPanels(colorPanels);
class ListPanel extends AbstractColorChooserPanel
implements ListSelectionListener {
private JPanel labelPanel = new JPanel(),
listPanel = new JPanel();
private JList redList = new JList(), blueList = new JList(),
greenList = new JList();
private DefaultListModel redModel = new DefaultListModel(),
blueModel = new DefaultListModel(),
greenModel = new DefaultListModel();
private boolean isAdjusting = false;
public void updateChooser() {
if( ! isAdjusting) {
isAdjusting = true;
Color color = getColorFromModel();
int r = color.getRed(), g = color.getGreen(),
b = color.getBlue();
redList.setSelectedIndex(r);
redList.ensureIndexIsVisible(r);
blueList.setSelectedIndex(b);
blueList.ensureIndexIsVisible(b);
greenList.setSelectedIndex(g);
greenList.ensureIndexIsVisible(g);
isAdjusting = false;
protected void buildChooser() {
redList.setFixedCellWidth(50);
greenList.setFixedCellWidth(50);
blueList.setFixedCellWidth(50);
for(int i=0; i < 256; ++i) {
redModel.addElement(Integer.toString(i));
greenModel.addElement(Integer.toString(i));
blueModel.addElement(Integer.toString(i));
redList.setModel(redModel);
greenList.setModel(greenModel);
blueList.setModel(blueModel);
listPanel.setLayout(new GridLayout(0,3,10,0));
listPanel.add(new JScrollPane(redList));
listPanel.add(new JScrollPane(blueList));
listPanel.add(new JScrollPane(greenList));
labelPanel.setLayout(new GridLayout(0,3,10,0));
labelPanel.add(new JLabel("Red"));
labelPanel.add(new JLabel("Blue"));
labelPanel.add(new JLabel("Green"));
add(labelPanel, BorderLayout.NORTH);
add(listPanel, BorderLayout.CENTER);
redList.addListSelectionListener(this);
greenList.addListSelectionListener(this);
blueList.addListSelectionListener(this);
public void valueChanged(ListSelectionEvent e) {
int r = redList.getSelectedIndex(),
b = blueList.getSelectedIndex(),
g = greenList.getSelectedIndex();
if(r != -1 && g != -1 && b != -1)
getColorSelectionModel().setSelectedColor(
new Color(r,g,b));
public String getDisplayName() {
return "display name";
public Icon getSmallDisplayIcon() {
return null;
public Icon getLargeDisplayIcon() {
16.2.3 JColorChooser屬性
16.2.4 JColorChooser事件
16.2.5 JColorChooser類總結
16.2.6 AWT相容
16.3 本章回顧
略