12.2.6 使用JFileChoose和Java7增强的JColorChooser

12.2.6 使用JFileChoose和Java7增强的JColorChooser

JColorChooser

JColorChooser用于创建颜色选择器对话框,该类的用法非常简单,该类主要提供了如下两个静态方法

方法 描述
JColorChooser() Creates a color chooser pane with an initial color of white.
JColorChooser(Color initialColor) Creates a color chooser pane with the specified initial color.
JColorChooser(ColorSelectionModel model) Creates a color chooser pane with the specified ColorSelectionModel.

showDialog( Component component, String title, Color initialColor):

方法 描述
static Color showDialog(Component component, String title, Color initialColor) 显示一个模式的颜色选择器对话框,该方法返回用户所选颜色。其中component指定该对话框的parent组件,而title指定该对话框的标题,大部分时候都使用该方法来让用户选择颜色。
static Color showDialog(Component component, String title, Color initialColor, boolean colorTransparencySelectionEnabled) Shows a modal color-chooser dialog and blocks until the dialog is hidden.
static JDialog createDialog(Component c, String title, boolean modal, JColorChooser chooserPane, ActionListener okListener, ActionListener cancelListener) 该方法返回一个对话框,该对话框内包含指定的颜色选择器,该方法可以指定该对话框是模式的还是非模式的(通过modal参数指定),还可以指定该对话框内“确定”按钮的事件监听器(通过okListener参数指定)和“取消”按钮的事件监听器(通过cancelListener参数指定)。

Java7JColorChooser增加了一个HSV标签页,允许用户通过HSV模式来选择颜色。

程序 JColorchooser颜色选择器

下面程序改写了前一章的HandDraw程序,改为使用JPanel作为绘图组件,而且使用JColorchooser来弹出颜色选择器对话框。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import javax.swing.*;

public class HandDraw {
// 画图区的宽度
private final int AREA_WIDTH = 500;
// 画图区的高度
private final int AREA_HEIGHT = 400;
// 下面的preX、preY保存了上一次鼠标拖动事件的鼠标坐标
private int preX = -1;
private int preY = -1;
// 定义一个右键菜单用于设置画笔颜色
JPopupMenu pop = new JPopupMenu();
JMenuItem chooseColor = new JMenuItem("选择颜色");
// 定义一个BufferedImage对象
BufferedImage image = new BufferedImage(AREA_WIDTH, AREA_HEIGHT, BufferedImage.TYPE_INT_RGB);
// 获取image对象的Graphics
Graphics g = image.getGraphics();
private JFrame f = new JFrame("简单手绘程序");
private DrawCanvas drawArea = new DrawCanvas();
// 用于保存画笔颜色
private Color foreColor = new Color(255, 0, 0);

public void init() {
chooseColor.addActionListener(ae -> {
// 下面代码直接弹出一个模式的颜色选择对话框,并返回用户选择的颜色
// 1号代码
// foreColor = JColorChooser.showDialog(f, "选择画笔颜色", foreColor);
// 下面代码则弹出一个非模式的颜色选择对话框,
// 并可以分别为“确定”按钮、“取消”按钮指定事件监听器
// 2号代码 开始
final JColorChooser colorPane = new JColorChooser(foreColor);
JDialog jd = JColorChooser.createDialog(f, "选择画笔颜色", false, colorPane,
e -> foreColor = colorPane.getColor(), null);
// 2号代码 结束
jd.setVisible(true);
});
// 将菜单项组合成右键菜单
pop.add(chooseColor);
// 将右键菜单添加到drawArea对象中
drawArea.setComponentPopupMenu(pop);
// 将image对象的背景色填充成白色
g.fillRect(0, 0, AREA_WIDTH, AREA_HEIGHT);
drawArea.setPreferredSize(new Dimension(AREA_WIDTH, AREA_HEIGHT));
// 监听鼠标移动动作
drawArea.addMouseMotionListener(new MouseMotionAdapter() {
// 实现按下鼠标键并拖动的事件处理器
public void mouseDragged(MouseEvent e) {
// 如果preX和preY大于0
if (preX > 0 && preY > 0) {
// 设置当前颜色
g.setColor(foreColor);
// 绘制从上一次鼠标拖动事件点到本次鼠标拖动事件点的线段
g.drawLine(preX, preY, e.getX(), e.getY());
}
// 将当前鼠标事件点的X、Y坐标保存起来
preX = e.getX();
preY = e.getY();
// 重绘drawArea对象
drawArea.repaint();
}
});
// 监听鼠标事件
drawArea.addMouseListener(new MouseAdapter() {
// 实现鼠标松开的事件处理器
public void mouseReleased(MouseEvent e) {
// 松开鼠标键时,把上一次鼠标拖动事件的X、Y坐标设为-1。
preX = -1;
preY = -1;
}
});
f.add(drawArea);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
}

public static void main(String[] args) {
new HandDraw().init();
}

// 让画图区域继承JPanel类
class DrawCanvas extends JPanel {
private static final long serialVersionUID = -3097175472553624890L;

// 重写JPanel的paint方法,实现绘画
public void paint(Graphics g) {
// 将image绘制到该组件上
g.drawImage(image, 0, 0, null);
}
}
}

上面程序分别使用了两种方式来弹出颜色选择对话框,其中1号代码可弹出一个模式的颜色选择对话框,并直接返回用户选择的颜色。这种方式简单明了,编程简单。
如果程序有更多额外的需要,则使用程序2号代码,弹出一个非模式的颜色选择对话框(允许程序设定),并为“确定”按钮指定了事件监听器,而“取消”按钮的事件监听器为null(也可以为该按钮指定事件监听器)。
Swing的颜色选择对话框如图12.8所示:
这里有一张图片
从图12.8中可以看出,Swing的颜色选择对话框提供了5种方式来选择颜色,图中显示了HSV方式、CMYK方式的颜色选择器,除此之外,该颜色选择器还可以使用RGBHSL方式来选择颜色。
Java6时,ColorChooser只提供了三种颜色选择方式,图12.8中看到的HSVCMYK两种颜色选择方式都是新增的。

JFileChooser

JFileChooser的功能与AWT中的FileDialog基本相似,也是用于生成“打开文件”、“保存文件”对话框;与FileDialog不同的是,JFileChooser无须依赖于本地平台的GUI,它由100%纯Java实现,在所有平台上具有完全相同的行为,并可以在所有平台上具有相同的外观风格。

构造器

为了调用JFileChooser来打开一个文件对话框,必须先创建该对话框的实例,JFileChooser提供了多个构造器来创建JFileChooser对象,它的构造器总共包含两个参数。

方法 描述
JFileChooser() Constructs a JFileChooser pointing to the user’s default directory.
JFileChooser(File currentDirectory) Constructs a JFileChooser using the given File as the path.
JFileChooser(File currentDirectory, FileSystemView fsv) Constructs a JFileChooser using the given current directory and FileSystemView.
JFileChooser(String currentDirectoryPath) Constructs a JFileChooser using the given path.
JFileChooser(String currentDirectoryPath, FileSystemView fsv) Constructs a JFileChooser using the given current directory path and FileSystemView.
JFileChooser(FileSystemView fsv) Constructs a JFileChooser using the given FileSystemView.

currentDirectory:指定所创建文件对话框的当前路径
currentDirectoryPath:指定所创建文件对话框的当前路径
FileSystemView:用于指定基于该文件系统外观来创建文件对话框,如果没有指定该参数,则默认以当前文件系统外观创建文件对话框。

显示隐藏文件对话框

JFileChooser并不是JDialog的子类,所以不能使用setVisible(true)方法来显示该文件对话框,而是调用showXxxDialog()方法来显示文件对话框

建立文件对话框 步骤

使用JFileChooser来建立文件对话框并允许用户选择文件的步骤如下。

创建JFileChooser对象

  1. 采用构造器创建一个JFileChooser对象,该JFileChooser对象无须指定parent组件,这意味着可以在多个窗口中共用该JFileChooser对象。创建JFileChooser对象时可以指定初始化路径,如下代码所示。
1
2
//以当前路径创建文件选择器
JFileChooser chooser = new JFileChooser(".");

JFileChooser执行初始化操作

  1. 调用JFileChooser的一系列可选的方法对JFileChooser执行初始化操作。JChooser大致有如下几个常用方法。
指定默认选择的文件
方法 描述
void setSelectedFile(File file) 指定该文件选择器默认选择的文件
void setSelectedFiles(File[] selectedFiles) 指定该文件选择器默认选择多个文件

例如:

1
2
//默认选择当前路径下的123.jpg文件
chooser.setSelectedFile(new File("123.jpg"));

设置选择模式

方法 描述
void setFileSelectionMode(int mode) 在默认情况下,该文件选择器只能选择文件,通过调用该方法可以设置允许选择文件、路径、文件与路径,mode参数可以设置为:JFileChooser.FILES_ONLYJFileChooser.DIRECTORIES_ONLYJFileChooser.FILES_AND_DIRECTORIES

例如

1
2
// 设置既可选择文件,也可选择路径
chooser.setFileselectionMode (JFileChooser.FILES_AND_DIRECTORIES);

设置文件过滤器

如果让文件对话框实现文件过滤功能,则需要结合FileFilter类来进行文件过滤。JFileChooser提供了两个方法来安装文件过滤器。

方法 描述
void addChoosableFileFilter(FileFilter filter) 添加文件过滤器。通过该方法允许该文件对话框有多个文件过滤器。
void setFileFilter(FileFilter filter) 设置文件过滤器。一旦调用了该方法,将导致该文件对话框只有个文件过滤器。

设置文件视图

如果需要改变文件对话框中文件的视图外观,则可以结合FileView类来改变对话框中文件的视图外观。

打开文件对话框

调用showXxxDialog方法可以打开文件对话框,通常如下三个方法可用。

方法 描述
int showDialog(Component parent, String approveButtonText) 弹出文件对话框,该对话框的标题“同意”按钮的文本(默认是“保存”或“取消”按钮)由approveButtonText来指定。
int showOpenDialog(Component parent) 弹出文件对话框,该对话框具有默认标题,“同意”按钮的文本是“打开”。
int showSaveDialog(Component parent) 弹出文件对话框,该对话框具有默认标题,“同意”按钮的文本是“保存”。

当用户单击“同意”、“取消”按钮,或者直接关闭文件对话框时才可以关闭该文件对话框,关闭该对话框时返回一个int类型的值,分别是:JFileChooser.APPROVE_OPTIONJFileChooser.CANCEL_OPTIONJFileChooser.ERROR_OPTION
如果希望获得用户选择的文件,则通常应该先判断对话框的返回值是否为JFileChooser.APPROVE_OPTION,该选项表明用户单击了“打开”或者“保存”按钮

获取用户选择的文件

JFileChooser提供了如下两个方法来获取用户选择的文件或文件集。

方法 描述
File getSelectedFile() 返回用户选择的文件。
File[] getSelectedFiles() 返回用户选择的多个文件。

按上面的步骤,就可以正常地创建一个“打开文件”、“保存文件”对话框,整个过程非常简单。如果要使用FileFilter类来进行文件过滤,或者使用FileView类来改变文件的视图风格,则有一点麻烦。

FileFilter类

先看使用FileFilter类来进行文件过滤。Javajava.io包下提供了一个FileFilter接口,该接口主要用于作为File类的listFiles(FileFilter)方法的参数,也是一个进行文件过滤的接口。但此处需要使用位于javax.swing.Filechooser包下的FileFilter抽象类,该抽象类包含两个抽象方法。

方法 描述
abstract boolean accept(File f) 判断该过滤器是否接受给定的文件,只有被该过滤器接受的文件才可以在对应的文件对话框中显示出来。
abstract String getDescription() 返回该过滤器的描述性文本。

如果程序要使用FileFilter类进行文件过滤,则通常需要扩展该FileFilter类,并重写该类的两个抽象方法,重写accept()方法时就可以指定自己的业务规则,指定该文件过滤器可以接受哪些文件。
例如如下代码:

1
2
3
4
5
6
7
8
9
public boolean accept(File f){
//如果该文件是路径,则接受该文件
if (f.isDirectory())
return true;
// 只接受以.gif作为后缀的文件
if (f.getName().endswith(".gif"))
return true;
return false;
}

在默认情况下,JFileChooser总会在文件对话框的“文件类型”下拉列表中增加“所有文件”选项,但可以调用JFileChoosersetAcceptAllFileFilterUsed(false)来取消显示该选项

方法 描述
void setAcceptAllFileFilterUsed(boolean b) Determines whether the AcceptAll FileFilter is used as an available choice in the choosable filter list.

FileView

FileView类用于改变文件对话框中文件的视图风格,FileView类也是一个抽象类,通常程序需要扩展该抽象类,并有选择性地重写它所包含的如下几个抽象方法。

方法 描述
String getDescription(File f) 返回指定文件的描述
Icon getIcon(File f) 返回指定文件在FIleChooser对话框中的图标
String getName(File f) 返回指定文件的文件名
String getTypeDescription(File f) 返回指定文件所属文件类型的描述
Boolean isTraversable(File f) 当该文件是目录时,返回该目录是否是可遍历的

与重写FileFilter抽象方法类似的是,重写这些方法实际上就是为文件选择器对话框指定自定义的外观风格。通常可以通过重写getlcon()方法来改变文件对话框中的文件图标。

程序示例

下面程序是一个简单的图片查看工具程序,该程序综合使用了上面所介绍的各知识点。

上面程序中为“打开”菜单项指定事件监听器,当用户单击该菜单时,程序打开文件对话框,并将用户打开的图片文件使用Label在当前窗口显示出来。
重写了FileFilter类的accept()方法,该方法根据文件后缀来决定是否接受该文件,其要求是当该文件的后缀等于该文件过滤器的extensions集合的某一项元素时,则该文件是可接受的。
程序的①处代码禁用了JFileChooser中“所有文件”选项,从而让用户只能看到图片文件。

第四段粗体字代码用于重写FileView类的getlcon()方法,该方法决定JFileChooser对话框中文件文件夹的图标——图标文件就返回pict.Png图标,根文件夹就返回dsk.Png图标,而普通文件夹则返回folder.png图标
运行上面程序,单击“打开”菜单项,将看到如图129所示的对话框
图省略…
上面程序中的②处粗体字代码还用了JFileChooser类的setAccessory(JComponent new Accessory)方法为该文件对话框指定附件,附件将会被显示在文件对话框的右上角,如图12.9所示。该附件可以是任何Swing组件(甚至可以使用容器),本程序中使用一个JLabe组件作为该附件组件,该JLabel用于显示用户所选图片文件的预览图片。该功能的实现很简单:当用户选择的图片发生改变时,以用户所选文件创建ImageIcon,并将该ImageIcon设置成该Label的图标即可。

监听用户选择文件的变化

为了实现当用户选择图片发生改变时,附件组件的icon随之发生改变的功能,必须为JFileChooser添加事件监听器,该事件监听器负责监听该对话框中用户所选择文件的变化JComponent类中提供了个addPropertyChangeListener方法,该方法可以为该JFileChooser添加一个属性监听器,用于监听用户选择文件的变化。程序中第一段粗体字代码实现了用户选择文件发生改变时的事件处理器。