| ## 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.
| ©Copyright, Macmillan Computer Publishing. All rights reserved.