Skip to main content.

Web Based Programming Tutorials

Homepage | Forum - Join the forum to discuss anything related to programming! | Programming Resources

Java Unleashed Second Edition

Chapter 22 -- Working with Dialog Boxes

Chapter 22

Working with Dialog Boxes

by K. C. Hopson


CONTENTS


This chapter focuses on the Dialog class, which is the basis for writing dialog boxes in Java. The class is illustrated through several dialog box examples which provide tips about how to use some of the more obscure features of the 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 automatically through the Window class's pack() method; this method works with the Window layout (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, support for menus, and the ability to modify the system cursor to various states such as waiting or moving. For most GUI platforms, the frame's title bar is tied to system control boxes, such as minimize, maximize, or 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.

Figure 22.1 and Listing 22.1 present a simple Frame applet that changes the cursor to a state based on the button selected.

Figure 22.1: A Frame applet that changes the state of the cursor.


Listing 22.1. Code for the Frame class that changes the cursor state.

import java.awt.*;
import java.lang.*;
import java.applet.*;

// This applet simply starts up the frame used to
// show different frame cursors...
public class FrameCursorApplet extends Applet  {
    public void init() {
      // Create the frame with a title...
      new FrameCursor("Frame Cursors");
   }
}

// The frame for letting the user pick different
// cursors to display...
class FrameCursor extends Frame {
   // Create the frame with a title...
   public FrameCursor(String title) {
      // Call the superclass constructor...
      super(title);
      // Create a grid layout to place the buttons...
      setLayout(new GridLayout(3,2));
      // Add the buttons for choosing the cursor...
      add(new Button("Default"));
      add(new Button("Wait"));
      add(new Button("Hand"));
      add(new Button("Move"));
      add(new Button("Text"));
      add(new Button("SE Resize"));
      // Pack and display...
      pack();
      resize(300,200); // Make it a reasonable size...
      show();
   }

   // Handle events...
   public boolean handleEvent(Event e) {
      switch(e.id) {
         case e.WINDOW_DESTROY:
            dispose();  // Erase frame
            return true;
            case Event.ACTION_EVENT:
            if (e.target instanceof Button)
               SetCursor((Button)e.target);
            return true;
         default:
            return false;
      }
   }

   // Set the cursor based on the button chosen...
   void SetCursor(Button btn) {
      // Get the label of the button...
      String selection = btn.getLabel();
      //Set the cursor based on that label...
      if (selection.equals("Wait"))
            setCursor(Frame.WAIT_CURSOR);
      else if (selection.equals("Hand"))
            setCursor(Frame.HAND_CURSOR);
      else if (selection.equals("Move"))
            setCursor(Frame.MOVE_CURSOR);
      else if (selection.equals("Text"))
            setCursor(Frame.TEXT_CURSOR);
      else if (selection.equals("SE Resize"))
            setCursor(Frame.SE_RESIZE_CURSOR);
      else // Just use the default...
            setCursor(Frame.DEFAULT_CURSOR);
   }
}

The applet class, FrameCursorApplet, does little more than launch the main frame, FrameCursor. The constructor for this frame begins by calling the frame superconstructor. The sole parameter is the caption displayed on the title bar. The layout for the frame is then set: Although the default is BorderLayout, in this case you want a 3-by-2 grid matrix, hence the use of GridLayout. Next, the buttons are added to the frame, with names representing the cursor state to be selected. After all the components have been added, the pack() method is invoked so that the button placement can be optimized. Because this optimized placement results in a small frame (six buttons sized tightly around the label text doesn't take much space), the resize() method is called to make the frame larger. Finally, the frame is displayed with the show() method.

When a button is selected, the custom method setCursor() is invoked. This method takes the button label and figures out which cursor should be displayed. The Frame class's setCursor() method is used to set the cursor state; its parameter is a static integer defined as part of the Frame class.

The current state of the cursor can be retrieved with the getCursorType() method. The getTitle() and setTitle() frame methods can be used to get and set the title bar caption. Similarly, the getIconImage() and setIconImage() methods can be used to get and set the image display of an iconized frame.

Introduction to the Dialog Class

Like the Frame class, the Dialog class is a subclass of the Window class. 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 highlights 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 two constructors for the Dialog class. Both take a Frame object as a parameter; they also take a boolean flag that indicates whether the dialog box should be modal. If the flag is set to true, the dialog box is modal. The constructors differ only in a parameter that specifies whether the dialog box should have a title caption. It is this constructor that is used in the example that follows.

Figure 22.2 shows a variation of the applet introduced in the preceding section, except that a dialog box is used to change the cursor state. Listing 22.2 shows the code for the Dialog class, called ChangeCursorDialog. Note how similar the dialog box here is to the frame in Figure 22.1.

Figure 22.2: Using a dialog box to change the state of the cursor.


Listing 22.2. Code for the Dialog class that changes the cursor state.

import java.awt.*;
import java.lang.*;
import java.applet.*;

// Dialog that presents a grid of buttons
// for choosing the Frame cursor. A Cancel
// button exits the dialog...
class ChangeCursorDialog extends Dialog {
FrameMenuCursor fr;

// Create the dialog and store the title string...
public ChangeCursorDialog(Frame parent,boolean modal,String title) {

 // Create dialog with title
 super(parent,title,modal);
 fr = (FrameMenuCursor)parent;
 // The layout is Grid layout...
 setLayout(new GridLayout(3,2));

 // Add the button options
 add(new Button("Default"));
 add(new Button("Wait"));
 add(new Button("Hand"));
 add(new Button("Move"));
 add(new Button("Text"));
 add(new Button("Cancel"));

 // Pack and size for display...
 pack();
 resize(300,200);
}
// Look for button selections to
// change the cursor...
public boolean action(Event e,Object arg) {
     // If button was selected then exit dialog..
if (e.target instanceof Button) {
         // And possibly change the cursor...
         if (arg.equals("Default"))
            fr.setCursor(Frame.DEFAULT_CURSOR);
         if (arg.equals("Wait"))
            fr.setCursor(Frame.WAIT_CURSOR);
         if (arg.equals("Hand"))
            fr.setCursor(Frame.HAND_CURSOR);
         if (arg.equals("Move"))
            fr.setCursor(Frame.MOVE_CURSOR);
         if (arg.equals("Text"))
            fr.setCursor(Frame.TEXT_CURSOR);
         dispose();
    }
    return false;
}
}

You can declare the dialog box and instantiate it as follows:

ChangeCursorDialog dlg;
dlg = new ChangeCursorDialog(this,true,"Change the cursor");

When it is time to display the dialog box, you can declare this method:

dlg.show(); // Make the dialog visible...

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 you associate a color with the foreground and background states of text. Fig-ure 22.3 shows how the dialog box appears in a browser.

Figure 22.3: The color dialog box.

How the Color Dialog Box Is Used

When the 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 a list item, 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. The text can be updated with the color settings for the current list item when you select the Update button.

The Construction of the Color Dialog Box

Four classes are used to construct the color dialog box. The ChooseColorDialog class is a subclass of Dialog and controls the main display and control 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 according to that color. The ColoredCheckboxGroup class groups ColoredCheckbox items together so that they can function as part of a radio button group.

The discussion of the color dialog box begins with its underlying components. Listing 22.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, through 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 boxes can be selected.


Listing 22.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 is used to contain ColoredCheckbox objects. Its constructor creates a preselected number of colored checkboxes to be 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) {
      // Call the default constructor...
      super();
      // Create the checkboxes and store in panel and reference array...
      c[0] = new ColoredCheckbox(Color.black,"Black",this,false);
      p.add(c[0]);
      c[1] = new ColoredCheckbox(Color.cyan,"Cyan",this,false);
      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 constructing 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 see which radio button should be turned on.

The colorDisplay class is a Canvas derivative that draws text (specified in the displayText String variable) with a specified foreground and background color. Listing 22.4 highlights some of the more interesting features of the class.


Listing 22.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 text...
   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 through the size() method; this method is a standard part of subclasses of Component. It then fills in the background color through the setColor() and fillRect() methods of the Graphics class. The paint() 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 21, "Creating User Interface Components." When AWT constructs the display of a group of components, it works with the layouts to decide what position and size a component should have. Sometimes, you may want a component to exercise some input into what its size will be. You can invoke two methods of the Component class 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 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 information of the current font and calling the stringWidth() and getHeight() methods respectively.

Finally, the dialog box is ready to be constructed. Listing 22.5 highlights the declarations and methods used to construct the color dialog box.


Listing 22.5. The construction of the ChooseColorDialog class.

// Dialog box for choosing display colors...
public class ChooseColorDialog extends Dialog {
   Frame fr;   // What to update...
   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 int NORMAL_FORE = 0;
   static int NORMAL_BACK = 1;
   static int HILITE_FORE = 2;
   static int HILITE_BACK = 3;
   // Construct dialog to allow color to be chosen...
   public ChooseColorDialog(Frame parent,boolean modal) {
      // Create dialog with title
      super(parent,"Color Dialog",modal);
      fr = parent;
      // 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);

    // 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);
    colorGrp.setMatchingColor(Color.magenta);

    // Create 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();
    p.add(new Button("Update"));
    p.add(new Button("Cancel"));

    // Add to grid bag...
    gbc.gridwidth = GridBagConstraints.REMAINDER;
    g.setConstraints(p,gbc);
    add(p);
   }

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 have most of the space that is taken up by the list control set to half the dialog box size; the color checkboxes take up the other half (refer back to Figure 22.3). The key reason for doing this is to set the GridBagConstraint's 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 22.5 returns the desired dimensions of the dialog box. It 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.

Using the Dialog Box

Once the dialog box is displayed, its event loop is entered. Listing 22.6 details the dialog box's handleEvent() method. This code has several subtleties worth noting. Most of the work is performed when an action occurs, as indicated by the ACTION_EVENT method. When a button is selected, the argument of the Event object is set to the name of the button. The handleEvent() method looks at this name to decide what to do. If the name is Cancel, the dialog box is removed from the screen with the dispose() method, and control returns to the calling frame. You can use the Update button to set the colors according to what is currently highlighted.


Listing 22.6. The handleEvent() method of the ChooseColorDialog class.

// Wait for Cancel or OK buttons to be chosen...
public boolean handleEvent(Event e) {
    switch(e.id) {
       case Event.ACTION_EVENT:
         // Kill the dialog...
         if (e.arg.equals("Cancel")) {
            dispose();  // Remove Dialog...
            return true;
         }  // end if
         // Update colors...
         if (e.arg.equals("Update")) {
            //  INSERT YOUR CODE HERE!
            return true;
         }  // end if
         if (e.target instanceof Checkbox) {
            selectedRadioItem();
            return false;
         }
         return false;
       // User selected a listbox item...
       case Event.LIST_SELECT:
         // Set up caption colors and color choice highlight...
         if (e.target instanceof List) {
            selectedChoiceListItem();
            return false;
         }  // end list if
         return false;
       default:
         return false;
   } // end switch
}

If the target of the ACTION_EVENT is a checkbox, a radio button is selected and the selectedRadioItems() method is called. This method sets the colorDisplay object's foreground or background colors according to the radio button chosen and the current selection in the list.

If you click a list item, a LIST_SELECT event is issued. In this case, the selectedChoiceListItems() method is invoked. This method sets the colorDisplay object's settings according to the current list selection; this process must take into account both the foreground and background colors. The ColoredCheckboxGroup's setMatchingColor() method is called to set the radio button of the ColoredCheckbox object corresponding to the current list color.

Calling the Dialog Box

The Frame object is responsible for bringing up the color dialog box. It can declare a variable of the colorDialog 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; to make the dialog box, you must specifically call the show() method. The color dialog box overrides the show() method so that it can do some setup before the dialog box appears:

public synchronized void show() {
      super.show(); // Call the default show method...
      // Set the listbox default...
      choiceList.select(0);
      // Set up caption colors and color choice highlight...
      selectedChoiceListItem();
}

The last method called, selectedChoiceListItem(), sets the radio buttons and display canvas to values corresponding to the current list selection.

The Font Dialog Box Example

This discussion of the font dialog box example will not be as lengthy as the preceding overview 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 22.4 shows the font dialog box. It is based on the ChooseFontDialog class, which displays its components in a two-column style similar to the color dialog box. The current font family, style, and size are shown in a Canvas display object of the fontDisplay class. This class is very similar to the colorDisplay class.

Figure 22.4: 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 are set, the font's style is set to plain.

Every time one of these controls is changed, the font display is updated with a new font. This happens in the paintSample() method. Listing 22.7 shows the code for the paintSample() method and also features the full source code of the font dialog box.


Listing 22.7. The full source code of the font dialog box.

// Dialog box for choosing display colors...
public class ChooseFontDialog extends Dialog {
   Frame fr;   // What to update...
   List choiceList;  // List of color choices...
   fontDisplay d; // This is the text display...
   Choice choiceSize;  // Size of font...
   Checkbox checkItalics;
   Checkbox checkBold;
   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() {
      // SET YOUR DEFAULT FONT HERE!
      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);
   }

   // Wait for Cancel or OK buttons to be chosen...
   public boolean handleEvent(Event e) {
    switch(e.id) {
       case Event.ACTION_EVENT:
         // Kill the dialog...
         if (e.arg.equals("Cancel")) {
          dispose();  // Remove Dialog...
          return true;
         }  // end if
         // Update colors on the text…
         if (e.arg.equals("OK")) {
            //  YOUR UPDATE CODE GOES HERE!
            dispose();
            return true;
         }  // end if
         if (e.target instanceof Choice) {
            paintSample();
            return false;
         }  // end list if
         if (e.target instanceof Checkbox) {
            paintSample();
            return false;
         }  // end list if
         return false;
       // User selected a listbox item...
       case Event.LIST_SELECT:
         // Set up caption colors and color choice highlight...
         if (e.target instanceof List) {
            paintSample();
            return false;
         }  // end list if
         return false;
       default:
         return false;
      } // end switch
   }

   // The layout will call this to get the preferred size
   // of the dialog.  Make it big enough for the components
   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,height);
   }

   // 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]);
       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);
    // 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();
    p.add(new Button("OK"));
    p.add(new Button("Cancel"));
    // 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 constructor...
      // Set the font dialog started off with...
      setFont(defaultFont);
      // Set up defaults...
      setDefaultFont();
      pack();  // Compact...
      // Resize to fit everything...
      resize(preferredSize());
    }

   // Set the display canvas to show itself with
   // the currently selected font
   private synchronized void paintSample() {
      // Get the family 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 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 on the Windows 95 environment follows the Windows 95 Open dialog box conventions.

The FileDialog can be constructed to be in a mode to load a file or 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 it is displayed. After a choice has been made, the chosen file and directory can be retrieved with the getFile() and getDirectory() methods. The former 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 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 creating controls in an applet, with the difference that you may have to call pack() or the preferredSize() method to get the exact appearance you are after.

The other big issue with dialog boxes is related to security. Some browsers, like 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 status bar. In the worst case, the dialog box may not even appear or may be flagged with a security exception! As stated before, this is the case with the FileDialog class in Microsoft's Internet Explorer. For these reasons, dialog boxes must be used with great caution in applets. When all is said and done, dialog boxes may be best suited for standalone Java applications.