弹出窗口与选择器(一)

在第8章中,我们了解了顶层容器,例如JFrame与JApplet。另外,我们探讨了用来创建弹出窗口来显示信息或是获取用户输入的JDialog类。尽管JDialog类可以工作得很好,Swing组件集合同时提供了一些更为简单的方法来由弹出窗口获取用户输入,我们将会在本章进行探讨。

JOptionPane类对于显示信息,获取文本用户输入,或是获取问题答案十分有用。ProgressMonitor与ProgressMonitorInputStream类可以使得我们监视长时间任务的过程。另外,JColorChooser与JFileChooser类提供了特性弹出窗口用来由用户获取颜色选择,或是获取文件或目录名。通过使用这些类,我们的界面开发任务可以更为快速与简单的实现。

9.1 JOptionPane Class

JOptionPane是一个可以用来创建放在弹出窗口中的面板的一个特殊类。面板的目的是向用户显示信息或是由用户获取响应。要实现这一任务,面板在四个区域显示内容(如图9-1):

  • Icon:图标区域用来显示一个图标,标识显示给用户的信息类型。为特定的消息类型提供默认的图标是所安装的观感的责任,但是如果我们希望显示其他的图标类型,我们可以提供我们自己的图标。
  • Message:这一区域的基本目的是显示一个文本信息。另外,这一区域还可以包含其他的可选对象集合来使得消息提供更多的信息。
  • Input:输入区域允许用户提供消息的响应。响应可以是自由格式,文本域,或组合框中选择列表或是列表控件。要显示是或否类型的问题,应该使用按钮区域。
  • Button:按钮区域也可以用来获取用户输入。在这个区域的按钮选择通知了JOptionPane使用的结束。可以使用按钮标签的默认集合,或者我们可以显示任意数量的按钮,也可以没有,并使用我们所希望的标签。

Swing_9_1

所有这些区域都是可选的(尽管没有消息与按钮的面板使得选项面板毫无用处)。

除了作为一个在弹出窗口中具有四部分的面板以外,JOptionPane还具有自动将其自身放在一个弹出窗口中并管理用户响应的获取的能力。依据我们所提供给用户的GUI类型,他也可以将自身放在一个JDialog或是一个JInternalFrame中。借助于Icon与JButton组件集合,JOptionPane可以很容易配置来显示多种消息与输入对话框。

注意,因为JOptionPane可以自动将其自身放在一个JDialog中,所以我们并不需要直接创建JDialog。

9.1.1 创建JOptionPane

我们可以使用JOptionPane的七个构造函数或是使用本章稍后将会讨论的25个工厂方法来创建一个JOptionPane。当手动创建JOptionPane时,我们拥有最大的控制。然而,然后我们必须将其放在一个弹出窗口中,显示窗口,最后管理响应。

由于自动完成所有事情所提供的方法的简便,我们也许会认为当使用JOptionPane时应只使用工厂方法。然而,通过本章,我们将会发现手动完成一些事情的其他原因。另外,当我们使用一个可视化编程环境时,环境会将JOptionPane看作一个JavaBean组件,并且会忽略其工厂方法。

对于七个构造函数,我们可以有6个不同参数的不同组合。参数可以使得我们配置图9-1中所显示的不同区域的一部分。六个参数是消息,消息类型,可选类型,图标,选项数组,以及初始的选项设置。参数的用法与工厂方法相同。

我们首先来看一下七个构造函数,然后探讨不同的参数。注意构造参数是级联的,并且只在前一个构造函数中添加额外的参数。

public JOptionPane()
JOptionPane optionPane = new JOptionPane();
 
public JOptionPane(Object message)
JOptionPane optionPane = new JOptionPane("Printing complete");
 
public JOptionPane(Object message, int messageType)
JOptionPane optionPane = new JOptionPane("Printer out of paper",
  JOptionPane.WARNING_MESSAGE);
 
public JOptionPane(Object message, int messageType, int optionType)
JOptionPane optionPane = new JOptionPane("Continue printing?", 
  JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_OPTION);
 
public JOptionPane(Object message, int messageType, int optionType,
  Icon icon)
Icon printerIcon = new ImageIcon("printer.jpg");
JOptionPane optionPane = new JOptionPane("Continue printing?", 
  JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_OPTION, printerIcon);
 
public JOptionPane(Object message, int messageType, int optionType, Icon icon,
  Object options[ ])
Icon greenIcon = new DiamondIcon(Color.GREEN);
Icon redIcon = new DiamondIcon(Color.RED);
Object optionArray[] = new Object[] { greenIcon, redIcon} ;
JOptionPane optionPane = new JOptionPane("Continue printing?", 
  JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_OPTION, printerIcon,
  optionArray);
 
public JOptionPane(Object message, int messageType, int optionType, Icon icon,
  Object options[], Object initialValue)
JOptionPane optionPane = new JOptionPane("Continue printing?", 
  JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_OPTION, printerIcon,
  optionArray, redIcon);

JOptionPane消息参数

message参数是一个Object,而不是一个String。当我们通常将一个引起来的字符串作为Object的参数时,我们仅仅可以在消息区域显示我们希望显示的任何内容。在本章稍后的“理解消息属性”一节中,我们将会了解这一参数的高级用法。然而,概括来说,有四个基本的规则可以解释Object类型消息参数意义。对于Object中的元素,依次遵循下列规则:

  • 如果消息是一个对象数组(Object[]),会使得JOptionPane在单独行放置每一项。
  • 如果消息是一个Component,则将该组件放置在消息区域。
  • 如果消息是一个Icon,会在JLable中放置Icon,并且在消息区域显示标签。
  • 如果消息是一个Object,使用toString()方法将其转换为String,将String放在JLabel中,并在消息区域显示标签。

JOptionPane消息类型与图标参数

messageType构造函数参数用来表示显示在JOptionPane中的消息类型。如果我们没有为JOptionPane指定自定义的图标,已安装的观感使用messageType参数设置来决定在图标区域使用哪个图标。JOptionPane提供了五个不同的消息类型常量:

  • ERROR_MESSAGE用来显示一个错误消息
  • INFORMATION_MESSAGE用来显示一个信息提示消息
  • QUESTION_MESSAGE用来显示一个查询消息
  • WARNING_MESSAGE用来显示一个警告消息
  • PLAIN_MESSAGE用来显示任何其他类型的消息

如果我们使用了同时带有messageType与icon作为参数的构造函数,并且希望JOptionPane为messageType使用默认图标,只需要将icon参数的值指定为null。如果icon参数不为null,则会使用所指定的图标,而不论是何种消息类型。

如果没有指定构造函数的messageType参数,则默认的消息类型为PLAIN_MESSAGE。

JOptionPane选项类型参数

optionType构造函数参数用来决定按钮区域的按钮集合配置。如果提供了一个下面所描述的options参数,则optionType参数会被忽略,而按钮集合配置则会由options获取。JOptionPane有四个不同的选项类型常量:

  • DEFAULT_OPTION用于一个OK按钮
  • OK_CANCEL_OPTION用来OK与Cancel按钮
  • YES_NO_CANCEL_OPTION用于Yes,No与Cancel按钮
  • YES_NO_OPTION用于Yes与No按钮

如果没有指定optionType构造函数参数,则默认的选项类型为DEFAULT_OPTION。

JOptionPane选项以及初始值参数

options参数是一个用来构建用在JOptionPane按钮区域的JButton对象集合的Object数组。如果这个参数为null(或者是使用了一个没有这个参数的构造函数),则按钮标签会由optionType参数来决定。否则,这个数组的作用类似于消息参数,但是并不支持迭代数组:

  • 如果options数组元素是一个Component,则会将这个组件放在按钮区域。
  • 如果options数组元素是一个Icon,则会将这个Icon放在一个JButton中,然后将按钮放在按钮区域。
  • 如果options数组元素是一个Object,则使用toString()方法将其转换为一个String,将这个String放在一个JButton中,然后将按钮放在按钮区域。

通常,options参数是一个String对象的数组。也许我们希望JButton上带有一个Icon,尽管最终的按钮不会带有标签。如果我们希望按钮上同时带有图标与文本标签,我们可以手动创建一个JButton,并将其放在一个数组中。相对的,我们可以在数组中直接包含其他任意的Component。然而对于后两种方法有一个小问题。我们要负责处理组件选中的响应,并且通知JOptionPane用户何时选择了这个组件。本章稍后的“向按钮区域添加组件”将会讨论如何正确处理这种行为。

当options参数不为null时,initialValue参数可以指定当面板初始显示时哪一个按钮是默认按钮。如果其为null,则按钮区域的第一个组件为默认按钮。在任何一种情况下,第一个按钮会获得输入焦点,除非在消息区域有一个输入组件,在这种情况下,输入组件会获得初始输入焦点。

9.1.2 显示JOptionPane

在我们使用一个构造函数创建了JOptionPane之后,我们所获得的是一个使用组件填充的面板。换句话说,所获得的JOptionPane还没有位于弹出窗口中。我们需要创建一个JDialog,一个JinternalFrame,或是其他的弹出窗口,然后将JOptionPane放在其中。另外,如果我们选择JOptionPane构造的这种手动风格,我们需要处理弹出窗口的关闭。我们必须监听按钮区域组件的选中,然后在选中之后隐藏弹出窗口。

因为在这里有如此多的工作要做,JOptionPane包含两个助手方法来将JOptionPane放在一个JDialog或是一个JInternalFrame之中,并且处理前面所描述的所有行为:

public JDialog createDialog(Component parentComponent, String title)
public JInternalFrame createInternalFrame(Component parentComponent, String title)

注意,当使用createDialog()与createInternalFrame()方法创建弹出窗口时,自动创建的按钮的选中会导致所创建的弹出窗口的关闭。然后我们需要使用getValue()方法来查询JOptionPane用户选中的选项,而且如果需要,可以使用getInputValue()方法获得输入值。

方法的第一个参数是弹出窗口所在的组件。第二个参数是弹出窗口的标题。一旦我们创建了弹出窗口,无论他是一个JDialog还是一个JInternalFrame,我们要显示他。然后弹出窗口会在按钮区域的一个组件被选中之后关闭,此时,我们的程序继续。下面的代码行演示了显示在一个JDialog中的JOptionPane的创建。所创建的弹出窗口显示在图9-2中。

JOptionPane optionPane = new JOptionPane("Continue printing?",
  JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_OPTION); 
JDialog dialog = optionPane.createDialog(source, "Manual Creation");
dialog.setVisible(true);

Swing_9_2

我们创建了JOptionPane,将其放在一个弹出窗口中,显示弹出窗口,并且用户响应之后,我们需要确定用户的选择是什么。选择是通过JOptionPane的public Object getValue()方法来提供的。getValue()方法返回的值是通过是否向JOptionPane构造函数提供了一个options数组来确定的。如果我们提供了这个数组,则会返回选中的参数。如果我们没有提供数组,则会返回一个Integer对象,而其值表示了选中的按钮在按钮区域中的位置。在另一种情况下,如果没有选择任何内容,getValue()方法会返回null,例如当通过选择弹出窗口标题的相应装饰关闭JDialog时。

为了更容易获取这种多面响应,列表9-1显示了一个OptionPaneUtils类,其中定义了方法public static int getSelection(JOptionPane optionPane)。指定一个选项面板,这个方法会将选中值的位置作为int返回,而不论是否提供了选项数组。为了标识没有选中任何内容,JOptionPane.CLOSED_OPTION(-1)会被返回。

package swingstudy.ch09;
 
import javax.swing.JOptionPane;
 
public final class OptionPaneUtils {
 
	private OptionPaneUtils() {
 
	}
 
	public static int getSelection(JOptionPane optionPane) {
		// Default return value, signals nothing selected
		int returnValue = JOptionPane.CLOSED_OPTION;
 
		// Get selected value
		Object selectedValue = optionPane.getValue();
		// if none, then nothing selected
		if(selectedValue != null) {
			Object options[] = optionPane.getOptions();
			if(options == null) {
				// default buttons, no array specified
				if(selectedValue instanceof Integer) {
					returnValue = ((Integer)selectedValue).intValue();
				}
			}
			else {
				// array of option buttons specified
				for(int i=0, n=options.length; iif(options[i].equals(selectedValue)) {
						returnValue = i;
						break; // out of for loop
					}
				}
			}
		}
		return returnValue;
	}
}

借助于这个新的OptionPaneUtils.getSelection(JOptionPane)助手方法,现在我们可以使用一行代码来确定选项面板的选择,并依据响应执行动作。

int selection = OptionPaneUtils.getSelection(optionPane);
switch (selection) {
  case ...: ...
    break;
  case ...: ...
    break;
  default: ...
}

如果我们使用一个null选项数组创建一个JOptionPane,我们可以使用JOptionPane类中的常量来标识默认按钮标签的位置以及由OptionPaneUtils.getSelection(JOptionPane)方法返回的值。这些常量列在表9-1中。使用这些常量可以使用我们避免硬编码常量,例如0,1,2或是-1。

Swing_table_9_1

9.1.3 在弹出窗口中自动创建JOptionPane

我们可以手动创建JOptionPane,将其放在一个JDialog或是JInternalFrame中,并获取响应。相对的,我们可以使用JOptionPane工厂方法在JDialog或是JInternalFrame中直接创建JOptionPane组件。使用工厂方法,我们可以使用一行代码创建一个选项面板,将其放在一个弹出窗口中,并且获取响应。

有25个工厂方法,可以分为两类:创建显示在JDialog中的JOptionPane或是创建显示在JInternalFrame中的JOptionPane。在JInternalFrame中显示JOptionPane的方法以showInternalXXXDialog()的方式命名,而创建显示在JDialog中的面板则以showXXXDialog()的方式命名。

JOptionPane的工厂方法的第二个分组是填充方法名字中的XXX部分。这表示了我们可以创建并显示的选项面板的各种消息类型。另外,消息类型定义了用户在选项面板中选择某个组件之后所返回的内容。四个不同的消息类型如下:

  • Message:对于消息弹出窗口,没有返回值。所以其方法定义为void show[Internal]MessageDialog(...)。
  • Input:对于输入弹出窗口,返回值或者是用户在文本域中所输入的内容(String),或者是用户在选项列表中的选择(Object)。所以,依据我们所使用的版本,show[Internal]InputDialog(...)方法或者返回一个String,或者返回一个Object。
  • Confirm:对于确认弹出窗口,返回值标识了用户在选项面板内选择的按钮。在一个按钮被选中后,弹出窗口消失,而返回值是显示在表9-1中的整数常量中的一个。所以,在这里方法定义为int show[Interal]ConfirmDialog(...)。
  • Option:对于选项弹出窗口,返回值是一个int,与确认弹出窗口的返回值类型相同,所以方法定义为itn show[Internal]OptionDialog(...)。如果按钮标签是通过一个非null的参数手动指定的,整数表示所选择的按钮的位置。

表9-2中的信息应该可以帮助我们理解25个方法及其参数。方法名(与返回类型)显示在表的左侧,而其参数列表(与数据类型)显示在右侧。对于每个方法名跨越各个列重复出现的数字标识了此方法的一个特定的参数集合。例如,showInputDialog行在父组件列,消息列,标题列以及消息类型列显示了一个3.所以,showInputDialog方法的一个版本定义如下:

public static String showInputDialog(Component parentComponent, Object message, String title, int messageType)

由于定义了不同的showXXXDialog()方法,我们不再需要亲自确定所选中的按钮或是用户的输入。依据所显示的对话框类型,各种方法的返回值是下列值中的一个:无返回值(void返回类型),表9-1中的int,String或是Object。

Swing_table_9_2

工厂方法的JOptionPanl参数

几乎工厂方法的所有参数都匹配JOptionPane的构造函数参数。本章前面的“创建JOptionPane”中的两个列表描述了消息类型与选项类型参数的可接受的值。另外,同时描述了消息,选项以及初值参数用法。父组件以及标题参数被传递给createDialog()或是createInternalFrame()方法,这依赖于JOptionPane所嵌入的弹出窗口的类型。

接下来我们需要考虑的是showInputDialog()方法的选择值参数以及初始选中值参数。对于输入对话框,我们可以向用户要求文本输入,并且允许用户输入任何内容,或者是我们可以向用户展示一个预定义的选项列表。showInputDialog()的选择值参数决定了我们如何提供该选项集合。初始选择值表示当JOptionPane首次显示时被选择的特定项。观感将会依据所展示的选项数目来决定义要使用的相应Swing组件。对于较小的列表,可以使用JComboBox。对于大的列表,对于Motif,Metal/Ocean以及Windows观感,多于20将会使用JList。

Swing_table_9_3

消息弹出窗口

sowMessageDialog()与showInternalDialog()方法使用弹出标题“Message”创建一个INFORMATION_MESSAGE弹出窗口,除非我们为消息类型与窗口标题指定了不同的参数设置。因为消息对话框的目的就是要显示一个信息,这些对话框只提供了OK按钮,并且没有返回值。图9-3显示了使用下面的代码所创建的示例消息弹出窗口:

JOptionPane.showMessageDialog(parent, "Printing complete"); JOptionPane.showInternalMessageDialog(desktop, "Printing complete");

Swing_9_3

确认弹出窗口

showConfirmDialg()与showInternalConfirmDialog()方法默认情况下使用QUESTION_MESSAGE类型以及“Select an Option”弹出标题创建一个确认弹出窗口。因为确认对话框询问一个问题,其默认选项类型为YES_NO_CANCEL_OPTION,为其指定Yes,No以及Cancel按钮。对这些方法的调用所获得的返回值是下列JOptionPane常量中的一个:YES_OPTION,NO_OPTION或是CANCEL_OPTION。我们可以很容易猜到哪一个常量对应哪一个按钮。图9-4显示了使用下面代码创建的确认弹出窗口:

JOptionPane.showConfirmDialog(parent, "Continue printing?");
JOptionPane.showInternalConfirmDialog(desktop, "Continue printing?");

Swing_9_4

输入弹出窗口

默认情况下,showInputDialog()与showInternalInputDialog()方法使用“Input”弹出标题创建一个QUESTION_MESASGE弹出窗口。输入对话框的选项类型为OK_CANCEL_OPTION,为其指定一个OK与一个Cancel按钮,而且选项类型是不可以改变的。这些方法的返回数据类型或者是一个String,或者是一个Object。如果我们没有指定选项值,弹出窗口会向用户展示一个文本域,并且将输入作为一个String返回。如果我们指定了选项值,我们会由选项值数组中获取一个Object。图9-5显示了使用下面代码所创建的输入弹出窗口:

JOptionPane.showInputDialog(parent, "Enter printer name:");
// Moons of Neptune
String smallList[] = { 
  "Naiad", "Thalassa", "Despina", "Galatea", "Larissa", "Proteus",
  "Triton", "Nereid"} ;
JOptionPane.showInternalInputDialog(desktop, "Pick a printer", "Input",
  JOptionPane.QUESTION_MESSAGE, null, smallList, "Triton");
// Twenty of the moons of Saturn
String bigList[] = {"Pan", "Atlas", "Prometheus", "Pandora", "Epimetheus",
  "Janus", "Mimas", "Enceladus", "Telesto", "Tethys", "Calypso", "Dione",
  "Helene", "Rhea", "Titan", "Hyperion", "Iapetus", "Phoebe", "Skadi",
  "Mundilfari"};
JOptionPane.showInputDialog(parent, "Pick a printer", "Input",
  JOptionPane.QUESTION_MESSAGE, null, bigList, "Titan");

Swing_9_5

选项弹出窗口

showOptionDialg()与showInternalOptionDialog()方法提供了最大的灵活性,因为他们允许我们所有的参数。他们没有默认参数,并且返回值是一个int。如果没有指定options参数,则返回值为表9-1中所列出的常量之一。否则,返回值表示了所选择的选项在options参数中的组件位置。图9-6显示了使用下列代码创建的多个输入弹出窗口,其中在按钮上提供了图标(而不是文本):

Icon greenIcon = new DiamondIcon(Color.GREEN);
Icon redIcon = new DiamondIcon(Color.RED);
Object iconArray[] = { greenIcon, redIcon} ;
JOptionPane.showOptionDialog(source, "Continue printing?", "Select an Option",
  JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, iconArray,
  iconArray[1]);
Icon blueIcon = new DiamondIcon(Color.BLUE);
Object stringArray[] = { "Do It", "No Way"} ;
JOptionPane.showInternalOptionDialog(desktop, "Continue printing?",
  "Select an Option", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE,
blueIcon, stringArray, stringArray[0]);

Swing_9_6

9.1.4 JOptionPane属性

表9-3显示了JOptionPane的15个属性。这些属性只有在我们没有使用JOptionPane的工厂方法时才可以访问。对于大多数参数来说,其意义直接与一个构造函数参数相对应。

Swing_table_9_5

对于输入对话框或是当selectionValues属性不为null时,wantsInput属性会自动被设置为true。inputValue属性是由一个输入对话框中选择的项。value属性标识了由按钮区域所做的选项。

显示多行消息

默认情况下maxCharacterPerLineCount属性设置为一个极大的值,Integer.MAX_VALUE。由于某些奇怪的原因,Swing开发选择不为这个属性提供一个setter方法。如果我们需要修改这个属性,我们必须继承JOptionPane并且重写public int getMaxCharacterPerLineCount()方法。这使得一个长的文本被分为选项面板中的多行。另外,我们不能使用任何的工厂方法,因为他们并不知道我们的子类。

为了帮助我们创建短小的JOptionPane组件,我们可以将列表9-2中所示的代码添加到前面列表9-1中所示的OptionPaneUtils类义中。这个新方法提供了指定所需要的选项面板字符宽度的方法。

public static JOptionPane getNarrowOptionPane(int maxCharacterPerLineCount) {
		// our inner class definition
		class NarrowOptionPane extends JOptionPane {
			int maxCharacterPerLineCount;
 
			NarrowOptionPane(int maxCharacterPerLineCount) {
				this.maxCharacterPerLineCount = maxCharacterPerLineCount;
			}
 
			public int getMaxCharacterPerLineCount() {
				return maxCharacterPerLineCount;
			}
		}
		return new NarrowOptionPane(maxCharacterPerLineCount);
	}

一旦定义了这个方法与新类,我们可以创建指定字符宽度的选项面板,手动配置所有的属性,将其放在一个弹出窗口中,显示弹出窗口,然后确定用户的响应。下面的代码演示了使用这个新的功能:

String msg = "this is a really long message ... this is a really long message";
JOptionPane optionPane = OptionPaneUtils.getNarrowOptionPane(72);
optionPane.setMessage(msg);
optionPane.setMessageType(JOptionPane.INFORMATION_MESSAGE);
JDialog dialog = optionPane.createDialog(source, "Width 72");
dialog.setVisible(true);

图9-7显示了我们没有修改maxCharacterPerLineCount属性时对话框的样子。图9-7同时显示新的短小JOptionPane的样子。

Swing_9_7

尽管这看起来需要大量的工作,这却是创建多行选项面板的最好方法,除非我们要手动将消息分析为单行。

理解消息属性

在本章前面所有使用JOptionPane构造函数的消息参数以及使用工厂方法的例子中,消息仅是一个字符串。正如在前面“JOptionPane消息参数”一节中所描述的,这个参数并不需要是一个字符串。例如,如果这个参数是一个字符串数组,每一个字符串就会在单独的行上显示。这就减少了使用短小JOptionPane的必要,但是需要我们自己计算字符。然而,因为我们是在分割消息,我们可以使用25个厂方法中的一个。例如,下面的代码创建了图9-8中显示的弹出窗口。

String multiLineMsg[] = { "Hello,", "World"} ;
JOptionPane.showMessageDialog(source, multiLineMsg);

Swing_9_8

消息参数不仅仅支持显示字符串数组,同时他还可以支持任意对象类型的数组。如果数组中的元素是一个Component,他会被直接放置在消息区域中。如果其元素是一个Icon,图标会被放置在一个JLabel中,然后JLabel被放置在消息区域。所有其他的对象会被转换为一个String,将其放在一个JLabel中,并且在消息区域显示,除非对象本身是一个数组;在这种情况下,规则会被迭代应用。

为了演示这种可能性,图9-9显示了JOptionPane的真正功能。实际的内容并不是要显示特定的内容,只是为了表明我们可以显示多种不同的内容。消息参数是由下面的数组构成的:

Object complexMsg[] = { 
   "Above Message", new DiamondIcon(Color.RED), new JButton("Hello"),
  new JSlider(), new DiamondIcon(Color.BLUE), "Below Message"} ;

Swing_9_9

向消息区域添加组件

如果我们要显示图9-9中的弹出窗口,我们就会注意到一个小问题。选项面板并不了解所嵌入的JSlider的设置,这与他自动了解JTextField,JComboBox或是JList组件的输入不同。如果我们希望JOptionPane获取JSlider值,我们需要使得我们的输入组件修改JOptionPane的inputValue属性。当这个值被修改时,选项面板会通知弹出窗口关闭,因为JOptionPane已经获取其输入值。

将一个ChangeListener关联到JSlider组件可以使得我们确定其值何时发生变化。向前面的列表9-1中显示的OptionPaneUtils类中添加另一个方法可以使得我们更为容易的重用JOptionPane中的这个特殊的JSlider。在列表9-3中以粗体显示了重要的方法调用。相似的代码行需要添加到我们希望在JOptionPane中使用的任意输入组件上。这一行会在用户修改了输入组件的值时通知选项面板。

public static JSlider getSlider(final JOptionPane optionPane) {
		JSlider slider = new JSlider();
		slider.setMajorTickSpacing(10);
		slider.setPaintTicks(true);
		slider.setPaintLabels(true);
		ChangeListener chageListener =  new ChangeListener() {
			public void stateChanged(ChangeEvent event) {
				JSlider theSlider = (JSlider)event.getSource();
				if(!theSlider.getValueIsAdjusting()) {
					optionPane.setInputValue(new Integer(theSlider.getValue()));
				}
			}
		};
		slider.addChangeListener(chageListener);
		return slider;
	}

现在创建了这个特殊的JSlider,我们需要将其放置在一个JOptionPane中。这需要我们后动创建JOptionPane组件,奇怪的是,并不要求wantsInput属性的设置。只有当我们希望JOptionPane来提供其自己的输入组件时,wantsInput属性才会被设置为true。因为我们正在提供这样的组件,所以就不需要这个属性。最终弹出窗口显示在图9-10中。

JOptionPane optionPane = new JOptionPane();
JSlider slider = OptionPaneUtils.getSlider(optionPane);
optionPane.setMessage(new Object[] { "Select a value: " , slider} );
optionPane.setMessageType(JOptionPane.QUESTION_MESSAGE);
optionPane.setOptionType(JOptionPane.OK_CANCEL_OPTION);
JDialog dialog = optionPane.createDialog(source, "My Slider");
dialog.setVisible(true);
System.out.println ("Input: " + optionPane.getInputValue());

Swing_9_10

注意,如果用户并没有移动滑块,JOptionPane.getInputValue()会返回JOptionPane.UNINITIALIZED_VALUE。

向按钮区域添加组件

在本章前面的“JOptionPane选项以及初始值参数”一节中,如果我们在JOptionPane的选项数组中有一个Component,我们必须自己配置组件来处理选中。对于我们通过options属性添加其他组件也是如此。当组件被配置为处理选中时,当组件被选中时,JOptionPane被嵌入的弹出窗口会显示。按钮的默认设置如此工作。当安装我们自己的组件时,我们必须通过设置选项面板的value属性在一个组件被选中时通知选项面板。

为了演示这种机制,创建一个可以放置在选项中具有图标与文本标签的JButton。如果我们没有自己定义这个组件,选项面板仅支持按钮上标签或是图标的显示。当按钮被选中时,按钮会通过将选项面板的value属性设置为按钮当前的文本标签来通知选项面板他被选中。在前面的列表9-1中添加另一个方法来使用我们可以创建一个这样的按钮。列表9-4源码中以粗体显示的代码行是我们需要添加到其他我们希望与组件数组结合作为JOptionPane的选项属性的类似组件上的重要方法调用。这一行代码会在这个组件被选中后调用。

public static JButton getButton(final JOptionPane optionPane, String text, Icon icon) {
		final JButton button = new JButton(text, icon);
		ActionListener actionListener = new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				// return current text label, instead of argument to method
				optionPane.setValue(button.getText());
			}
		};
		button.addActionListener(actionListener);
		return button;
	}

在创建了这个特殊的JButton之后,我们需要将其放在一个JOptionPane中。不幸的,这也需要较长的JOptionPane使用。最终的弹出窗口显示在图9-11中。

JOptionPane optionPane = new JOptionPane();
optionPane.setMessage("I got an icon and a text label");
optionPane.setMessageType(JOptionPane.INFORMATION_MESSAGE);
Icon icon = new DiamondIcon (Color.BLUE);
JButton jButton = OptionPaneUtils.getButton(optionPane, "OK", icon);
optionPane.setOptions(new Object[] {jButton} );
JDialog dialog = optionPane.createDialog(source, "Icon/Text Button");
dialog.setVisible(true);

Swing_9_11

监听属性变化

JOptionPane类定义了下列11个常量来辅助监听边界属性的变化:

  • ICON_PROPERTY
  • INITIAL_SELECTION_VALUE_PROPERTY
  • INITIAL_VALUE_PROPERTY
  • INPUT_VALUE_PROPERTY
  • MESSAGE_PROPERTY
  • MESSAGE_TYPE_PROPERTY
  • OPTION_TYPE_PROPERTY
  • OPTIONS_PROPERTY

SELECTION_VALUES_PROPERTY

  • VALUE_PROPERTY
  • WANTS_INTUT_PROPERTY

如果我们没有使用JOptionPane的工厂方法,我们可以使用PropertyChangeListener来监听边界属性的变化。这可以使得我们被动的监听边界属性的变化,而不是在变化后主动获取。

9.1.5 自定义JOptionPane观感

每一个可安装的Swing观感都提供了不同的JOptionPane外观以及默认的UIResource值集合。图9-12显示了预安装的观感类型Motif,Windows,以及Ocean的JOptionPane窗口的外观。

Swing_9_12

JOptionPane的消息类型帮助确定要在选项面板的图标区域显示的默认图标。对于普通的消息,并没图标。其余的四个图标-用于信息,问题,警告以及错误消息-显示在表9-4中。

Swing_table_9_6

表9-5中显示了JOptionPane可用的UIResource相关属性的集合。对于JOptionPane组件,有56种不同的属性。

Swing_table_9_7_1Swing_table_9_7_2Swing_table_9_7_3Swing_table_9_7_4

表9-5中所列资源的一个很好的用法就是用来自定义默认的按钮标签从而来匹配用户的locale或是语言。例如,要将Cancel,No,OK以及Yes按钮的标签修改为法语,可以在我们的程序中添加下面的代码。(我们也可以由java.util.ResourceBundle中获取翻译的文本。)

// Set JOptionPane button labels to French
UIManager.put("OptionPane.cancelButtonText", "Annuler");
UIManager.put("OptionPane.noButtonText", "Non");
UIManager.put("OptionPane.okButtonText", "D'accord");
UIManager.put("OptionPane.yesButtonText", "Oui");

现在当我们显示在选项面板时,按钮将会具有本地化的按钮标签。当然,这需要为选项面板翻译消息。图9-13显示在下面的代码所创建的弹出窗口的样子。因为弹出窗口的标题并不是一个属性,我们必须将标题传递给每一个所创建的对话框。

int result = JOptionPane.showConfirmDialog(
  aFrame, "Est-ce que vous avez 18 ans ou plus?", "Choisisez une option",
  JOptionPane.YES_NO_CANCEL_OPTION);

Swing_9_13

JOptionPane组件支持本地化的JOptionPane按钮标签。JOptionPane可以为标准的Yes,No,Cancel与OK按钮显示相庆的中文或是日文按钮标签。例如,图9-14中左侧显示了带有日文标签的Yes,No与Cancel按钮标签,而右侧则显示了带有日文标签的OK与Cancel按钮标签。很明显,我们需要修改选项面板中的消息。

Swing_9_14

幸运的是,JDK 5.0版本包含了对于标签JOptionPane(同时还有JFileChooser与JColorChooser)标签的翻译。这可以用于德语(de),西班牙语(es),法语(fr),意大利语(it),日语(ja),韩语(ko),英语,瑞典语(sv),以及中文(简体/zh_CN与繁体/zh_TW)。

你可能感兴趣的:(弹出窗口)