Java 1.1 Unleashed
-23-
Working with Dialog Boxes
by K.C. Hopson
IN THIS CHAPTER
- Windows and Frames
- The Color Dialog Box Example
- The Font Dialog Box Example
- The FileDialog Class
This chapter focuses on the Dialog class, which is the basis for writing
dialog boxes in Java. The class is explained with several dialog box examples that
provide tips about how to use some of the more obscure features of Abstract Windowing
Toolkit (AWT). The FileDialog class is discussed at the end of this chapter.
To get a proper understanding of the Dialog class, however, it is important
to review how the Window and Frame classes work. This chapter begins
with a quick review of these two classes.
Windows and Frames
The Window class is used in AWT to create popup windows that appear outside
the constraints of the normal browser area allocated to an applet. Because the Window
class is derived from the Container class, it can contain other components.
Unlike applet components tied directly to a browser page, Window classes
are not restricted to a prespecified area of the screen. Window objects can be resized
as their immediate requirements dictate. AWT can perform this adjustment automatically
using the Window class's pack() method; this method works with
the Window layout manager (by default, BorderLayout) to arrive
at the optimal presentation of the window, given its contained components and screen
resolution. Typically, pack() is called before a window is displayed. Windows
are not made visible until the show() method is called. Windows are removed
from the screen and their resources are freed when the dispose() method
is invoked.
The Frame class extends the Window class by adding a title bar,
a border for resizing, and support for menus. For most GUI platforms, the frame's
title bar is tied to system control boxes, such as minimize, maximize, and destroy.
Consequently, the Frame class has all the elements necessary to make an
applet look like a "real" application, complete with menus and system controls.
Listing 23.1 presents a simple Frame applet that changes its title based
on the button selected. The applet class, FrameTestApplet, does little more
than launch the main frame, FrameTitles. The main listener class, FrameTitleListener,
simply takes action commands and sets the frame title to the command name. The constructor
for the frame itself, FrameTitles(), begins by calling the frame super constructor.
The sole parameter for the constructor is the caption displayed on the title bar.
The layout for the frame is then set. The default is BorderLayout, but because
we want a 3x2 grid matrix in this case, we use GridLayout. Then the buttons
are added to the frame, with names representing the new title of the frame. Each
button is hooked to the same instance of FrameTitleListener; when the button
is clicked, the listener is called, and the frame's title is changed. After all the
components have been added, another listener, FrameListener, is hooked to
the frame; this listener simply shuts down the frame when the user tries to close
it. Finally, the pack() method is invoked so that the button placement can
be optimized. Because this optimized placement results in a small frame (six buttons
placed closely around the label text doesn't take much space), the resize()
method is called to make the frame a larger size. Finally, the frame is displayed
with the show() method.
Listing 23.1. Code for the Frame applet that changes the
frame title.
import java.awt.*;
import java.awt.event.*;
import java.lang.*;
import java.applet.*;
// This applet simply starts up the frame use to
// show different frame titles...
public class FrameTestApplet extends Applet {
public void init() {
// Create the frame with a title...
new FrameTitles("Frame Titles");
}
}
// Listen for changes to the frame title
class FrameTitleListener implements ActionListener {
Frame fr; // Frame to use...
// Constructor...
public FrameTitleListener(Frame fr) {
this.fr = fr;
}
// Handle the action to be performed...
public void actionPerformed(ActionEvent e) {
// Get the action that occured...
String selection = e.getActionCommand();
fr.setTitle(selection);
}
}
// Handle close events...
class FrameListener implements WindowListener {
Frame fr; // Frame to use...
// Constructor...
public FrameListener(Frame fr) {
this.fr = fr;
}
// This closes the window...
public void windowClosing(WindowEvent e) {
fr.dispose();
}
public void windowOpened(WindowEvent e) {
}
public void windowClosed(WindowEvent e) {
}
public void windowIconified(WindowEvent e) {
}
public void windowDeiconified(WindowEvent e) {
}
}
// The frame for letting the user pick different
// titles to display...
class FrameTitles extends Frame {
// Create the frame with a title...
public FrameTitles(String title) {
// Call the superclass constructor...
super(title);
// Create a grid layout to place the buttons...
setLayout(new GridLayout(3,2));
// Create the listener...
// Add the buttons for choosing the titles...
FrameTitleListener listener = new FrameTitleListener(this);
Button b = new Button("Frame Title #1");
b.addActionListener(listener);
add(b);
b = new Button("Frame Title #2");
b.addActionListener(listener);
add(b);
b = new Button("Frame Title #3");
b.addActionListener(listener);
add(b);
b = new Button("Frame Title #4");
b.addActionListener(listener);
add(b);
b = new Button("Frame Title #5");
b.addActionListener(listener);
add(b);
b = new Button("Frame Title #6");
b.addActionListener(listener);
add(b);
// Have a listener for shutting down the frame...
addWindowListener(new FrameListener(this));
// Pack and display...
pack();
resize(300,200); // Make it a reasonable size...
show();
}
}
Introduction to the Dialog Class
Like the Frame class, the Dialog class is a subclass of Window.
Dialog boxes differ from frames in a couple of subtle ways, however. The most important
of these differences is that dialog boxes can be modal. When a modal dialog box is
displayed, input to other windows in the applet is blocked until the dialog box is
disposed. This feature points to the general purpose of dialog boxes, which is to
give the user a warning or a decision to be made before the program can continue.
Although support for nonmodal, or modeless, dialog boxes is supported, most dialog
boxes are modal.
There are three constructors for the Dialog class. All three take a Frame
object as an initial parameter, indicating the owner of the constructor. Two of the
constructors take an additional String parameter for the title, and one
constructor takes a third boolean parameter to indicate whether or not it
is a modal dialog box. Many of your dialog boxes will be modal, meaning that they
take all input from the user until the dialog box is destroyed.
Listing 23.2 shows the code of a variation of the applet in Listing 23.1; in this
second version, a dialog box is used to change the frame's title. A frame class,
called FrameMenuTest, and its corresponding listener, FrameMenuListener,
work with a menu that has two options: show the dialog box or quit using the dispose()
method. The dialog box is called ChangeTitleDialog. Notice that, like the
frame example, this dialog box example has two event listener classes.
The main thing to note about the code in this listing is how the dialog box is
instantiated in the FrameMenuListener class (the first parameter is FrameMenuTest):
ChangeTitleDialog dlg;
dlg = new ChangeCursorDialog(fr,true,"Change the cursor");
When it is time to display the dialog box, you can declare it as follows:
dlg.show(); // Make the dialog visible...
Notice how similar the dialog box in Listing 23.2 is to the frame in Listing 23.1.
Listing 23.2. Code for the Dialog class that changes the
frame title.
import java.awt.*;
import java.lang.*;
import java.applet.*;
import java.awt.event.*;
// This applet simply starts up the frame
// which provides a menu for setting the frame title...
public class DialogTestApplet extends Applet {
public void init() {
// Create the frame with a title...
new FrameMenuTest("Menu Based Test");
}
}
// Listen for changes to the frame title
class FrameMenuListener implements ActionListener {
// The dialog to change the title...
ChangeTitleDialog dlg;
Frame fr; // Frame to use...
// Constructor...
public FrameMenuListener(Frame fr) {
this.fr = fr;
// Instantiate the dialog...
dlg = new ChangeTitleDialog(fr,true,"Change the title");
}
// Handle the action to be performed...
public void actionPerformed(ActionEvent e) {
// Get the action that occured...
String selection = e.getActionCommand();
if (selection.equals("Quit"))
fr.dispose();
// Otherwise call the Dialog...
if (selection.equals("Change Title Dialog"))
dlg.show(); // Make the dialog visible...
}
}
// The frame that creates a dialog that
// changes the frame's title
class FrameMenuTest extends Frame {
// Create the frame with a title...
public FrameMenuTest(String title) {
// Call the superclass constructor...
super(title);
// Add the menus...
// First create the menu bar
MenuBar mbar = new MenuBar();
setMenuBar(mbar); // Attach to the frame...
// Add the File submenu...
Menu m = new Menu("File");
mbar.add(m); // Add to menu bar
// Create action listener for the menu items...
FrameMenuListener listener = new FrameMenuListener(this);
// Add Dialog to the submenu...
MenuItem item = new MenuItem("Change Title Dialog");
item.addActionListener(listener);
m.add(item);
// Add a separator
m.addSeparator();
// Add Quit to the submenu...
item = new MenuItem("Quit");
item.addActionListener(listener);
m.add(item);
// Pack and display...
pack();
resize(300,200); // Make it a reasonable size...
show();
}
}
// Listen for changes to the frame title
class DialogTitleListener implements ActionListener {
Frame fr; // Frame to use...
// Constructor...
public DialogTitleListener(Frame fr) {
this.fr = fr;
}
// Handle the action to be performed...
public void actionPerformed(ActionEvent e) {
// Get the action that occured...
String selection = e.getActionCommand();
fr.setTitle(selection);
}
}
// Handle close events...
class DialogListener implements WindowListener {
Dialog dlg; // Dialog to use...
// Constructor...
public DialogListener(Dialog dlg) {
this.dlg = dlg;
}
// This closes the window...
public void windowClosing(WindowEvent e) {
dlg.dispose();
}
public void windowOpened(WindowEvent e) {
}
public void windowClosed(WindowEvent e) {
}
public void windowIconified(WindowEvent e) {
}
public void windowDeiconified(WindowEvent e) {
}
}
// Dialog that presents a grid of buttons
// for changing the Frame title.
class ChangeTitleDialog extends Dialog {
Frame fr;
// Create the dialog and store the title string...
public ChangeTitleDialog(Frame parent,boolean modal,String title) {
// Create dialog with title
super(parent,title,modal);
fr = parent;
// Create a grid layout to place the buttons...
setLayout(new GridLayout(3,2));
// Add the buttons for choosing the titles...
DialogTitleListener listener = new DialogTitleListener(fr);
Button b = new Button("Frame Title #1");
b.addActionListener(listener);
add(b);
b = new Button("Frame Title #2");
b.addActionListener(listener);
add(b);
b = new Button("Frame Title #3");
b.addActionListener(listener);
add(b);
b = new Button("Frame Title #4");
b.addActionListener(listener);
add(b);
b = new Button("Frame Title #5");
b.addActionListener(listener);
add(b);
b = new Button("Frame Title #6");
b.addActionListener(listener);
add(b);
// Have a listener for shutting down the dialog...
addWindowListener(new DialogListener(this));
// Pack and size for display...
pack();
resize(300,200);
}
}
The Color Dialog Box Example
In this section, a color dialog box is created to further explain how to use the
Dialog class. The example lets the you associate a color with the foreground
and background states of the text. Figure 23.1 shows how the dialog box appears in
a browser.
How the Color Dialog Box Is Used
When the color dialog box appears, a list control at the top left of the dialog
box shows which elements of the text can be modified. These colors are normal foreground,
normal background, highlighted foreground, and highlighted background. When you select
an item from the list, the radio button for the corresponding color is highlighted.
A text display underneath the list shows what the text would look like with the given
colors. The text display shows either the normal state (with both foreground and
background colors) or the background state. If you select a new color with the radio
buttons, the Canvas object is updated to show what the new foreground and
background combination would look like. When you select the Update button,
the text is updated with the color settings for the current list item.
Figure 23.1.
The color dialog box.
The Construction of the Color Dialog Box
Four classes are used to construct the color dialog box. The ChooseColorDialog
class is a subclass of the Dialog class and controls the main display of
the dialog box. The colorDisplay class is a Canvas class derivative
that draws text with colors corresponding to the selected foreground and background
display. The ColoredCheckbox class draws a checkbox associated with a certain
Color object; the background of the box is drawn with that color. The ColoredCheckboxGroup
class groups ColoredCheckbox items together so that they can function as
part of a radio-button group. In addition to these main classes, there are three
listener classes attached to the dialog box.
The discussion of the color dialog box begins with its underlying components.
Listing 23.3 shows the code for the ColoredCheckbox class. Its most interesting
feature is that it associates itself with a given Color object. It paints
its background according to the Color object and, by using the setIfColorMatches()
method, turns its checkbox on if the color sent to it matches its internal color.
The checkbox in this case is a radio button because the class is associated with
a CheckboxGroup object. Checkbox objects have radio buttons only if they
are associated with a CheckboxGroup object; only one radio button in a checkbox
group can be selected at a time. If no checkbox group is specified for a checkbox
object, there are no restrictions on which checkboxes can be selected.
Listing 23.3. The ColoredCheckbox class.
// Class for creating a checkbox associated
// with a given color...
class ColoredCheckbox extends Checkbox {
Color color; // The color of this checkbox...
// Constructor creates checkbox with specified color...
public ColoredCheckbox(Color color, String label,
CheckboxGroup grp, boolean set) {
// Call the default constructor...
super(label,grp,set);
this.color = color;
setBackground(color);
}
// Sets itself to true if it matches the color
public void setIfColorMatches(Color match) {
if (color == match)
setState(true);
else
setState(false);
}
// Return the color matching this box...
public Color getColor() {
return color;
}
}
The ColoredCheckboxGroup class is used to contain ColoredCheckbox
objects. Its constructor creates a preselected number of colored checkboxes associated
with a Panel object. Here are the first few lines of the ColoredCheckboxGroup
class declaration:
class ColoredCheckboxGroup extends CheckboxGroup {
// Array to hold checkboxes...
ColoredCheckbox c[] = new ColoredCheckbox[12];
// Constructor. Create the checkboxes with
// no default color chosen...
public ColoredCheckboxGroup(Panel p,ItemListener listener) {
// Call the default constructor...
super();
// Create the checkboxes and store in panel and reference array...
c[0] = new ColoredCheckbox(Color.black,"Black",this,false);
c[0].addItemListener(listener);
p.add(c[0]);
c[1] = new ColoredCheckbox(Color.cyan,"Cyan",this,false);
c[1].addItemListener(listener);
p.add(c[1]);
Strangely enough, ColoredCheckboxGroup is not a Container object.
Consequently, the checkboxes must be associated with a Panel object to meet
the needs at hand. Note the use of the Color constants in the construction
of the ColoredCheckbox objects. The reference array (variable c)
is used in the other method of the class, setMatchingColor(), which is used
to set the radio button of the ColoredCheckbox object that matches a certain
color:
public void setMatchingColor(Color match) {
for (int i = 0; i < c.length; ++i)
c[i].setIfColorMatches(match);
}
Because ColoredCheckbox objects are self-identifying by color, this technique
prevents a long and cumbersome walk through hard-coded color names to determine which
radio button should be turned on.
You may also have noticed that an ItemListener class is attached to each
checkbox. This listener is called every time a checkbox is selected. As discussed
in the following section, "Using the Dialog Box," the listener is used
to set the colors for the dialog box whenever a color checkbox is selected.
The colorDisplay class is a Canvas derivative that draws text
(specified in the displayText string variable) with a specified foreground
and background color. Listing 23.4 highlights some of the more interesting features
of the colorDisplay class.
Listing 23.4. Portions of the colorDisplay class.
// The layout will call this to get the minimum size
// of the object. In this case, you want it to be at
// least big enough to fit the display test...
public Dimension minimumSize() {
// Get the metrics of the current font...
FontMetrics fm = getFontMetrics(getFont());
return new Dimension(fm.stringWidth(displayText),
2 * fm.getHeight());
}
// Paint the colors and text...
public synchronized void paint(Graphics g) {
if ((foreground == null) || (background == null))
return;
// Set background...
Dimension dm = size();
g.setColor(background);
g.fillRect(0,0,dm.width,dm.height);
// Draw the string
g.setColor(foreground);
// Set dimensions. Move just from left...
FontMetrics fm = getFontMetrics(getFont());
int x = fm.charWidth('W');
// And center in height...
int y = fm.getHeight();
g.drawString(displayText,x,y);
}
The paint() method draws the canvas if a background and foreground color
have been selected. The method starts by getting the size of its drawing area from
the size() method (a standard part of subclasses of Component).
The paint() method then fills in the background color using the setColor()
and fillRect() methods of the Graphics class. The method then sets
the color of the text to be displayed (the foreground). By getting the current FontMetrics,
the canvas can figure out a good location for the text string; the getHeight()
method returns the total height of the font. The drawString() method then
draws the text at the specified location.
The minimumSize() method is used with layouts, which are discussed in
Chapter 22, "Creating User Interface Components." When the AWT constructs
the display of a group of components, it works with the layouts to decide the position
and size of a component. Sometimes, you may want a component to have some input into
what its size will be. Two methods of the Component class can be invoked
to do this. The preferredSize() method returns the dimensions of the preferred
size of the component. The minimumSize() method returns the smallest size
in which the component should be made. For the colorDisplay() class, the
minimumSize() method returns the information that the component should be
wide enough to display the text string and twice as high as its current font. The
method does this by getting the FontMetrics of the current font and calling
the stringWidth() and getHeight() methods respectively.
Finally, the dialog box is ready to be constructed. Listing 23.5 shows the complete
code for the color dialog box. The createComponents() method adds the components
to the dialog box by using the complex GridBagLayout class. The main thing
to be done here is to set up the list control to take up most of one half of the
dialog box and to place the color checkboxes on the other half (refer back to Figure
23.1). The key reason for doing this is to set the GridBagConstraints weighty
and gridheight variables to the appropriate values. By setting the former
to 1.0, you tell the layout that the associated components should be given
preeminence in terms of the layout's height. When weighty is set to 0.0,
the height of the corresponding components is given lower priority.
The preferredSize() method in Listing 23.5 returns the desired dimensions
of the dialog box. The dialog box should be 3 times as wide as the longest string
in the list component, and 24 times as high as the current font. With these settings,
everything should fit comfortably in the dialog box.
Listing 23.5. The construction of the ChooseColorDialog
class.
// Dialog box for choosing display colors...
class ChooseColorDialog extends Dialog {
ColoredCheckboxGroup colorGrp; // To hold radio buttons of colors...
List choiceList; // List of color choices...
colorDisplay d; // This is the text display...
// Defines for listbox values...
static final int NORMAL_FORE = 0;
static final int NORMAL_BACK = 1;
static final int HILITE_FORE = 2;
static final int HILITE_BACK = 3;
Color normalForeColor;
Color normalBackColor;
Color highlightedForeColor;
Color highlightedBackColor;
// Construct dialog to allow color to be chosen...
public ChooseColorDialog(Frame parent,boolean modal) {
// Create dialog with title
super(parent,"Color Dialog",modal);
// Initialize the colors...
normalForeColor = Color.black;
normalBackColor = Color.white;
highlightedForeColor = Color.black;
highlightedBackColor = Color.white;
// Create the dialog components...
createComponents();
pack(); // Compact...
// Resize to fit everything...
resize(preferredSize());
}
// The layout will call this to get the preferred size
// of the dialog. Make it big enough for the listbox text
// the checkboxes, canvas, and buttons...
public Dimension preferredSize() {
// Get the metrics of the current font...
FontMetrics fm = getFontMetrics(getFont());
int width = 3 * fm.stringWidth("Highlighted foreground");
int height = 24 * fm.getHeight();
return new Dimension(width,height);
}
// Create the main display panel...
void createComponents() {
// Use gridbag constraints...
GridBagLayout g = new GridBagLayout();
setLayout(g);
GridBagConstraints gbc = new GridBagConstraints();
// Set the constraints for the top objects...
gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 1.0;
gbc.weighty = 1.0;
gbc.gridheight = 10;
// Add the listbox of choices...
choiceList = new List();
choiceList.addItem("Normal foreground");
choiceList.addItem("Normal background");
choiceList.addItem("Highlighted foreground");
choiceList.addItem("Highlighted background");
g.setConstraints(choiceList,gbc);
add(choiceList);
// Add the listeners...
ColorListboxListener listListener = new ColorListboxListener(this);
choiceList.addItemListener(listListener);
// Create the checkbox panel
Panel checkboxPanel = new Panel();
checkboxPanel.setLayout(new GridLayout(12,1));
// Create the checkbox group and add radio buttons...
colorGrp = new ColoredCheckboxGroup(checkboxPanel,new ColorCheckboxListener(this));
colorGrp.setMatchingColor(Color.magenta);
// Create add checkbox panel to right...
gbc.gridwidth = GridBagConstraints.REMAINDER;
g.setConstraints(checkboxPanel,gbc);
add(checkboxPanel);
// Display the color chosen...
d = new colorDisplay("This is how the text looks.");
// Add to grid bag...
gbc.weighty = 0.0;
gbc.weightx = 1.0;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.gridheight = 1;
g.setConstraints(d,gbc);
add(d);
// Two buttons: "Update" and "Cancel"
Panel p = new Panel();
ChooseActionListener listener = new ChooseActionListener(this);
Button b = new Button("Update");
b.addActionListener(listener);
p.add(b);
b = new Button("Cancel");
b.addActionListener(listener);
p.add(b);
// Add to grid bag...
gbc.gridwidth = GridBagConstraints.REMAINDER;
g.setConstraints(p,gbc);
add(p);
}
// Setup defaults upon showing...
public synchronized void show() {
super.show(); // Call the default show method...
// Set the listbox default...
choiceList.select(0);
}
// Update the global color fields with current settings...
public void update()
{
// Set canvas colors based on state...
int index = choiceList.getSelectedIndex();
switch (index) {
case NORMAL_FORE:
normalForeColor = d.getForeColor();
break;
case NORMAL_BACK:
normalBackColor = d.getBackColor();
break;
case HILITE_FORE:
highlightedForeColor = d.getForeColor();
break;
case HILITE_BACK:
highlightedBackColor = d.getBackColor();
break;
default:
break;
}
}
// Set up caption colors and color choice highlight
// according to current listbox value...
public void selectedChoiceListItem() {
Color fore,back; // Display canvas colors
// Set canvas colors based on state...
int index = choiceList.getSelectedIndex();
if ((index == NORMAL_FORE) || (index == NORMAL_BACK)) {
fore = normalForeColor;
back = normalBackColor;
}
// Otherwise its the background...
else {
fore = highlightedForeColor;
back = highlightedBackColor;
}
// Update the canvas...
d.setForeColor(fore);
d.setBackColor(back);
d.repaint();
// Update the color radio buttons...
Color radioColor;
// Even numbers are fore, odd are back...
if ((index % 2) == 0)
radioColor = fore;
else
radioColor = back;
colorGrp.setMatchingColor(radioColor);
}
// Update display canvas when radio color changes...
public void selectedRadioItem() {
// Get choice from Color box...
ColoredCheckbox box = (ColoredCheckbox)colorGrp.getCurrent();
Color color = box.getColor();
// If normal set canvas colors...
Color fore,back;
int index = choiceList.getSelectedIndex();
// Set background or foreground color based on
// current listbox selection...
if ((index == NORMAL_FORE) || (index == HILITE_FORE))
d.setForeColor(color);
else
d.setBackColor(color);
// Repaint the canvas...
d.repaint();
}
}
Using the Dialog Box
Three listener classes are used to control the actions of the color dialog box.
They are tied to the dialog box in the createComponents() method of the
ChooseColorDialog class. The first class, ColorListboxListener,
is called whenever an item in the list is selected. The ColorListboxListener
class is based on the ItemListener interface, which invokes the itemStateChanged()
method when an item is selected from the list. The ColorCheckboxListener
class is similar to the ItemListener interface except that it is called
when checkboxes (in this case, radio buttons) are selected. The ColorCheckboxListener
class notifies the dialog box that a new color has been displayed. Finally, the ChooseActionListener
class is used to indicate which of the two buttons has been selected: The Update
button permanently sets a color, and the Cancel button causes the dialog
box to be destroyed.
Listing 23.6. The listener classes of the color dialog
box.
// Listeners for the Color Dialog
// This one is for the listbox...
class ColorListboxListener implements ItemListener {
ChooseColorDialog dlg; // The color dialog...
// Constructor...
public ColorListboxListener(ChooseColorDialog dlg) {
this.dlg = dlg;
}
// Handle the action to be performed...
public void itemStateChanged(ItemEvent e) {
dlg.selectedChoiceListItem();
}
}
// This one is for the checkboxes......
class ColorCheckboxListener implements ItemListener {
ChooseColorDialog dlg; // The color dialog...
// Constructor...
public ColorCheckboxListener(ChooseColorDialog dlg) {
this.dlg = dlg;
}
// Handle the action to be performed...
public void itemStateChanged(ItemEvent e) {
dlg.selectedRadioItem();
}
}
class ChooseActionListener implements ActionListener {
// Actions on the dialog...
ChooseColorDialog dlg; // The color dialog...
// Constructor...
public ChooseActionListener(ChooseColorDialog dlg) {
this.dlg = dlg;
}
// Handle the action to be performed...
public void actionPerformed(ActionEvent e) {
// Get the action that occured...
String selection = e.getActionCommand();
if (selection.equals("Update"))
dlg.update();
// Otherwise destroy the Dialog...
if (selection.equals("Cancel"))
dlg.dispose();
}
}
Calling the Dialog Box
The Frame object is responsible for displaying the color dialog box.
It can declare a variable of the color dialog class as follows:
ChooseColorDialog colorDialog; // Color Dialog...
In its constructor, the frame instantiates the color dialog box with the following
call:
colorDialog = new ChooseColorDialog(this, true);
This code fragment states that the frame is the parent of the dialog box and its
appearance is modal. Recall that a modal dialog box does not allow input to other
windows while it is being displayed.
A dialog box does not automatically appear when it is constructed; you display
the dialog box with a specific call to the show() method.
The Font Dialog Box Example
The discussion of the font dialog box example is not as lengthy as the preceding
discussion of the color dialog box. In many ways, the two examples are similar, so
a detailed explanation of the font dialog box isn't required.
Figure 23.2 shows the font dialog box. It is based on the ChooseFontDialog
class, which displays its components in a two-column style similar to that of the
color dialog box. The current font family, style, and size is shown in a Canvas
display object of the fontDisplay class, which is very similar to the colorDisplay
class.
Figure 23.2.
The font dialog box.
The list component on the left side of the dialog box shows the fonts available
on the current platform. It uses the AWT Toolkit class to get this information.
Here is the code that creates the control and adds the font families:
// Add the listbox of choices...
// Get the selection from the toolkit...
choiceList = new List();
String fontList[] = Toolkit.getDefaultToolkit().getFontList();
for (int i = 0; i < fontList.length; ++i)
choiceList.addItem(fontList[i]);
A choice box is added to the dialog box to enumerate font sizes that can be used.
Two checkboxes are used to set the bold and italicized styles. If none of these options
are selected, the font's style is set to plain.
Every time one of these controls changes, the font display is updated to show
the change. This change happens in the paintSample() method, as shown in
Listing 23.7.
Listing 23.7. The full source code for the font dialog
box.
// Listeners for the Font Dialog
// This one is for the all the repaint routines...
class FontItemListener implements ItemListener {
ChooseFontDialog dlg; // The color dialog...
// Constructor...
public FontItemListener(ChooseFontDialog dlg) {
this.dlg = dlg;
}
// Handle the action to be performed...
public void itemStateChanged(ItemEvent e) {
dlg.paintSample();
}
}
class ChooseActionListener implements ActionListener {
// Actions on the dialog...
ChooseFontDialog dlg; // The color dialog...
// Constructor...
public ChooseActionListener(ChooseFontDialog dlg) {
this.dlg = dlg;
}
// Just shutdown...
public void actionPerformed(ActionEvent e) {
dlg.dispose();
}
}
// Dialog box for choosing display colors...
class ChooseFontDialog extends Dialog {
List choiceList; // List of color choices...
fontDisplay d; // This is the text display...
Choice choiceSize; // Size of font...
Checkbox checkItalics;
Checkbox checkBold;
Frame fr;
Font currentFont; // Current font in sample...
Font defaultFont; // Store font dialog was created with...
// Construct dialog to allow color to be chosen...
public ChooseFontDialog(Frame parent,boolean modal) {
// Create dialog with title
super(parent,"Font Dialog",modal);
fr = parent;
defaultFont = getFont();
// Create the dialog components...
createComponents();
}
// Get the default font and set up display...
private void setDefaultFont() {
// Get the latest font...
currentFont = getFont();
// Get default list...
String s = currentFont.getName();
int index = findListString(choiceList,s);
if (index >= 0)
choiceList.select(index);
else
choiceList.select(0);
// Get default size
int sizeFont = currentFont.getSize();
index = findChoiceString(choiceSize,
String.valueOf(sizeFont));
if (index >= 0)
choiceSize.select(index);
else
choiceSize.select(0);
// Set the style displays...
int styleFont = currentFont.getStyle();
if ((styleFont & Font.BOLD) != 0)
checkBold.setState(true);
else
checkBold.setState(false);
if ((styleFont & Font.ITALIC) != 0)
checkItalics.setState(true);
else
checkItalics.setState(false);
// Set the canvas style...
d.setFont(currentFont);
}
// The layout will call this to get the preferred size
// of the dialog. Make it big enough for the listbox text
// the checkboxes, canvas, and buttons...
public Dimension preferredSize() {
// Get the metrics of the current font...
FontMetrics fm = getFontMetrics(getFont());
int width = 3 * fm.stringWidth("Highlighted foreground");
int height = 14 * fm.getHeight();
return new Dimension(width + 40,height + 40);
}
// Create the main display panel...
private void createComponents() {
// Use gridbag constraints...
GridBagLayout g = new GridBagLayout();
setLayout(g);
GridBagConstraints gbc = new GridBagConstraints();
// Set the constraints for the top objects...
gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 1.0;
gbc.weighty = 1.0;
gbc.gridheight = 10;
// Add the listbox of choices...
// Get the selection from the toolkit...
choiceList = new List();
String fontList[] = Toolkit.getDefaultToolkit().getFontList();
for (int i = 0; i < fontList.length; ++i) {
choiceList.addItem(fontList[i]);
} // end if
g.setConstraints(choiceList,gbc);
add(choiceList);
// Set the default values...
gbc.weighty = 0.0;
gbc.weightx = 1.0;
gbc.gridheight = 1;
gbc.gridwidth = GridBagConstraints.REMAINDER;
// Create a label for display...
Label l = new Label("Size:");
// Add to grid bag...
g.setConstraints(l,gbc);
add(l);
// Create the choice box...
choiceSize = new Choice();
choiceSize.addItem("8");
choiceSize.addItem("10");
choiceSize.addItem("12");
choiceSize.addItem("14");
choiceSize.addItem("16");
choiceSize.addItem("20");
// Add to grid bag...
g.setConstraints(choiceSize,gbc);
add(choiceSize);
// Add Italics...
checkItalics = new Checkbox("Italics");
g.setConstraints(checkItalics,gbc);
add(checkItalics);
// Add Bold...
checkBold = new Checkbox("Bold");
g.setConstraints(checkBold,gbc);
add(checkBold);
// Set listeners...
FontItemListener itemListener = new FontItemListener(this);
choiceList.addItemListener(itemListener);
choiceSize.addItemListener(itemListener);
checkItalics.addItemListener(itemListener);
checkBold.addItemListener(itemListener);
// Display the color chosen...
d = new fontDisplay("Sample Text");
// Add to grid bag...
g.setConstraints(d,gbc);
add(d);
// Two buttons: "OK" and "Cancel"
Panel p = new Panel();
ChooseActionListener actionListener = new ChooseActionListener(this);
Button b = new Button("OK");
b.addActionListener(actionListener);
p.add(b);
b = new Button("Cancel");
b.addActionListener(actionListener);
p.add(b);
// Add to grid bag...
gbc.gridwidth = GridBagConstraints.REMAINDER;
g.setConstraints(p,gbc);
add(p);
}
// Setup defaults upon showing...
public void show() {
setFont(defaultFont);
// Set up defaults...
setDefaultFont();
pack(); // Compact...
// Resize to fit everything...
resize(preferredSize());
// Set the font dialog started off with...
super.show(); // Call the default constructor...
}
// Set the display canvas to show itself with
// the currently selected font
public synchronized void paintSample() {
// Get the familty to display
String fontName = choiceList.getSelectedItem();
// Get its point size
String fontSize = choiceSize.getSelectedItem();
// Set its style
int fontStyle = Font.PLAIN;
if (checkItalics.getState())
fontStyle += Font.ITALIC;
if (checkBold.getState())
fontStyle += Font.BOLD;
// Create a font with the proper attributes...
currentFont = new Font(fontName,fontStyle,
Integer.parseInt(fontSize));
// Set the new font on the canvas...
d.setFont(currentFont);
// Repaint it so the new font is displayed..
d.repaint();
}
// Return index of string in list...
// -1 means not found
public int findListString(List l,String s) {
for (int i = 0; i < l.countItems(); ++i) {
if (s.equals(l.getItem(i)) )
return i;
}
return -1;
}
// Return index of string in choice...
// -1 means not found
public int findChoiceString(Choice c,String s) {
for (int i = 0; i < c.countItems(); ++i) {
if (s.equals(c.getItem(i)) )
return i;
}
return -1;
}
}
// A small class that illustrates the
// current highlight and background
class fontDisplay extends Canvas {
String displayText;
// Construct the display by storing the
// text to be displayed...
public fontDisplay(String displayText) {
super();
this.displayText = displayText;
}
// The layout will call this to get the minimum size
// of the object. In this case we want it to be at
// least big enough to fit the display test...
public Dimension minimumSize() {
// Get the metrics of the current font...
FontMetrics fm = getFontMetrics(getFont());
return new Dimension(fm.stringWidth(displayText),
4 * fm.getHeight());
}
// Paint the colors and text...
public synchronized void paint(Graphics g) {
// Set background...
Dimension dm = size();
g.setColor(Color.white);
g.fillRect(0,0,dm.width,dm.height);
// Draw the string
g.setColor(Color.black);
// Set dimensions. Move just from left...
FontMetrics fm = getFontMetrics(getFont());
int x = fm.charWidth('I');
// And center in height...
int y = fm.getHeight();
g.drawString(displayText,x,y);
}
}
The FileDialog Class
The FileDialog class is a subclass of Dialog and is used to
provide a platform-independent approach to letting the user select the files to be
loaded or saved. Instances of the FileDialog class usually mirror the underlying
GUI conventions. For example, a FontDialog object for loading a file in
the Windows 95 environment follows the Windows 95 Open dialog box conventions.
The FileDialog object can be constructed in the mode to load a file or
in the mode to save a file. These dialog boxes look similar but perform slightly
differently. For example, the Save version of the dialog box notifies the user that
a file exists if a filename is given for a preexisting file. Here's the code you
need to construct dialog boxes for both the load and save cases:
FileDialog openFileDialog; // File Open Dialog...
FileDialog saveFileDialog; // File Save Dialog...
openFileDialog = new FileDialog(this,"Open File",
FileDialog.LOAD);
saveFileDialog = new FileDialog(this,"Save File",
FileDialog.SAVE);
The integer flag in the last parameter of the constructors indicates the mode
in which the dialog box should function.
When the dialog box is displayed with the show() method, it acts in a
modal fashion so that input to the frame is blocked while the dialog box is displayed.
After a choice has been made, the chosen file and directory can be retrieved with
the getFile() and getDirectory() methods. The getFile()
method returns a null value if the user cancels out of the dialog box.
It is interesting to note that the FileDialog objects constructed here
do not appear when the applet is run in Netscape Navigator. For security reasons,
Netscape does not allow any file-based methods to be invoked from an applet. In the
latest incarnation of Microsoft Internet Explorer, you actually get a security exception
if you even attempt to reference the FileDialog class! Consequently, the
FileDialog class is really useful only for standalone applications.
Summary
As the examples in this chapter have shown, most of the work in creating a dialog
box is setting up the component controls. The techniques for doing this are very
similar to those for creating controls in an applet, with the difference that you
may have to call the pack() or preferredSize() method to give your
dialog box the exact appearance you want.
The other big issue with dialog boxes is related to security. Some browsers, such
as Netscape Navigator, consider dialog boxes to be a possible security threat. For
this reason, a warning or an "untrusted window" message may appear in the
browser's status bar. In the worst case, the dialog box may not even appear or may
be flagged with a security exception (as is the case with the FileDialog
class in the Microsoft Internet Explorer). For these reasons, you must use great
caution when placing dialog boxes in applets. When all is said and done, dialog boxes
may be best suited for standalone Java applications.
|