95.106 - Design and Implementation of Computer Applications
2001

 5 Menus and Dialogs


What's in This Set of Notes?


 5.1 Creating Menus

What is Menu?

What are the main Menu Classes?


How Does it all "Hook" Together ?

This diagram shows how all these components hook together.  Basically ....


Adding a JMenuBar to a JFrame?

Adding a JMenu to a JMenuBar?

Adding a JMenuItem to a JMenu?

Adding a JRadioButtonMenuItem to a JMenu?

Adding a Cascaded Menu to a JMenu?

Creating a Popup Menu ?

Other Settings for MenuItems:


 5.2 Menu Events

How do you set up and respond to Menu events ?  Well, MenuItems work just like buttons.  So...we just have to implement the ActionListener interface as we did with buttons. How do you set up and respond to the JPopupMenu events ?   This type of menu is meant to pop up anywhere, not just from a menu.   As a result, we cannot merely use an ActionListener, we are forced to use a MouseListener so that we can have the menu "work" on any chosen area of the window.  We use the show() method to make the menu pop up.  It takes the parent pane as a parameter as well as the width and height of the menu. Notice that we can ask the mouse event for its modifiers.  This lets us get information about which button has been pressed.  The InputEvent class has defined constants.  The constant indicating that the right button was pressed is the InputEvent.BUTTON3_MASK.  Note that this code only brings up the popup menu but does not handle selection of menu items.  To do that, we do something similar to that of regular menus.


Example:

In this example, we investigate the use of a menubar with menus as well as cascaded menus and a popup menu.  The example has no purpose other than to show you how the different menus are created and used.   Here are screen snapshots that show the menus that we'll create in this example:
 


A standard menu

A cascaded menu

A menu with radio buttons

A pop-up menu

The example shows how the use of many menu items can lead to a lot of instance variables.  In addition, we use a common event handler for all menu items and apply a dispatching strategy which calls the appropriate react method for the given menu item.  We could have omitted the react methods and merely placed all this code within the single event handler but this could look messy if the react methods are large.

How would the example look if we used anonymous classes instead of one event handler ?  It may not save much in code size but we only need to update the class in one place instead of two when a menu item is added or removed! Also, we might not need to keep all the menu items in instance variables! Why not give it a try and see what it looks like.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

public class FileMenuExample extends JFrame implements ActionListener {

// Use instance variables to keep track of menu items and popup menus
JMenuItem thinkItem = new JMenuItem("Think", new ImageIcon("brain.gif"));
JMenuItem copyItem = new JMenuItem("Copy");
JMenuItem newItem = new JMenuItem("New");
JMenuItem openItem = new JMenuItem("Open");
JMenuItem saveAsItem = new JMenuItem("Save As");
JMenuItem findItem = new JMenuItem("Find");
JMenuItem replaceItem = new JMenuItem("Replace");

// Some items for use in the Settings menu
JMenuItem appleItem = new JRadioButtonMenuItem("Apples");
JMenuItem orangeItem = new JRadioButtonMenuItem("Oranges");
JMenuItem bannanaItem = new JRadioButtonMenuItem("Bannanas");

// Use instance variables to keep track of a popup menu and its items
JPopupMenu popupMenu = new JPopupMenu();
JMenuItem  helpItem = new JMenuItem("help");
JMenuItem  inspectItem = new JMenuItem("inspect");

// Add a constructor for our frame.
public FileMenuExample(String title) {

super(title);

// Create a menu bars and its pull-down menus
JMenuBar menuBar = new JMenuBar();
JMenu  fileMenu = new JMenu("File");
JMenu  editMenu = new JMenu("Edit");
JMenu  settingsMenu = new JMenu("Settings");
JMenu  searchMenu = new JMenu("Search");

// set menu accelerators for Alt keys
fileMenu.setMnemonic('F');
editMenu.setMnemonic('E');
settingsMenu.setMnemonic('S');
newItem.setMnemonic('N');
openItem.setMnemonic('O');

// set receiver as the object to handle menu item selection requests
newItem.addActionListener(this);
openItem.addActionListener(this);
saveAsItem.addActionListener(this);
thinkItem.addActionListener(this);
copyItem.addActionListener(this);
findItem.addActionListener(this);
replaceItem.addActionListener(this);
helpItem.addActionListener(this);
inspectItem.addActionListener(this);

ButtonGroup  fruits = new ButtonGroup();
fruits.add(appleItem);
fruits.add(orangeItem);
fruits.add(bannanaItem);

// add menu items in the menus
fileMenu.add(newItem);
fileMenu.add(openItem);
fileMenu.add(saveAsItem);
editMenu.add(thinkItem);
editMenu.add(copyItem);
searchMenu.add(findItem);
searchMenu.add(replaceItem);
settingsMenu.add(appleItem);
settingsMenu.add(orangeItem);
settingsMenu.add(bannanaItem);

// add items to the popup menu
popupMenu.add(helpItem);
popupMenu.add(inspectItem);

//create the cascaded menu
editMenu.add(searchMenu);

// add menus to the menu bar
menuBar.add(fileMenu);
menuBar.add(editMenu);
menuBar.add(settingsMenu);

// add menu bar to window and popup menu to the window pane
setJMenuBar(menuBar);

// add popup menu to the window pane
popupMenu.setInvoker(getContentPane());

// register the event handler for the popup menu
getContentPane().addMouseListener(new MouseInputAdapter() {
    public voidmouseClicked(MouseEvent event){
       if (event.getModifiers() == InputEvent.BUTTON3_MASK)
            popupMenu.show(getContentPane(), 100, 100);
    }});
// Set the background of the frame
setBackground(Color.lightGray);

}
// dispatch menu selections
public void actionPerformed(ActionEvent event){
if (event.getSource() == newItem)
    reactToNewMenuSelection();
else if (event.getSource() == openItem)
    reactToOpenMenuSelection();
else if (event.getSource() == saveAsItem)
    reactToSaveAsMenuSelection();
else if (event.getSource() == copyItem)
    reactToCopyMenuSelection();
else if (event.getSource() == thinkItem)
    reactToThinkMenuSelection();
else if (event.getSource() == findItem)
    reactToFindMenuSelection();
else if (event.getSource() == replaceItem)
    reactToReplaceMenuSelection();
else if (event.getSource() == helpItem)
    reactToHelpMenuSelection();
else if (event.getSource() == inspectItem)
    reactToInspectMenuSelection();
}
// Here are all the react methods for the menu items
public void reactToNewMenuSelection() {
    System.out.println("reacting to NEW selection from menu");
}
public void reactToOpenMenuSelection() {
    System.out.println("reacting to OPEN selection from menu");
}
public void reactToSaveAsMenuSelection() {
    System.out.println("reacting to SAVE AS selection from menu");
}
public void reactToThinkMenuSelection() {
    System.out.println("reacting to THINK selection from menu");
}
public void reactToCopyMenuSelection() {
    System.out.println("reacting to COPY selection from menu");
}
public void reactToFindMenuSelection() {
    System.out.println("reacting to FIND selection from menu");
}
public void reactToReplaceMenuSelection() {
    System.out.println("reacting to REPLACE selection from menu");
}
public void reactToHelpMenuSelection() {
    System.out.println("reacting to HELP selection from popup menu");
}
public void reactToInspectMenuSelection() {
    System.out.println("reacting to INSPECT selection from popup menu");
}
public static void main(String args[]) {
    FileMenuExample frame =  new FileMenuExample("FileMenu Example");
    frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
    frame.setSize(300, 300);
    frame.setVisible(true);
}
}

 5.3 Dialog Boxes

What is a Dialog Box ?

There are two important terms: Here is how everything should work:

Notice that the model is used as the "middle-man" between the two windows:

How do we make this interaction with the two windows ?  We make the client (i.e. original window) implement the following interface which we will define:
import javax.swing.*;
public interface DialogClientInterface {
     public void dialogFinished(JDialog aDialog);
     public void dialogCancelled(JDialog aDialog);
}
We also pass the client as a parameter to the dialog box so that the dialog box can send one of these two interface messages to the client upon closing.  The dialogFinished message is sent when the OK button is clicked, otherwise the dialogCancelled is sent.


How do You Make a Dialog Box Window ?


Example:

Here is a BankAccountDialog  that modifies a BankAccount's owner name.  We use the BankAccount class that was used in 95.105.  In this example, we'll just bring up the dialog box directly, but the client will be simple, with no window.

To start, we'll make a JPanel to form the "view" for the dialog box:

Notice: Here is some code that will test the panel out:
public static void main(String args[]) {
    JFrame frame = new JFrame("Test for BankAccount Panel");
    frame.getContentPane().add(new BankAccountPanel(new BankAccount("Bob", 100)));
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(300, 100);
    frame.setVisible(true);

    JFrame frame2 = new JFrame("Test for BankAccount Panel");
    frame2.getContentPane().add(new BankAccountPanel(new BankAccount("Betty", 500)));
    frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame2.setSize(300, 100);
    frame2.setVisible(true);
}


 

Now we'll make the actual Dialog box.  This is like a combined "controller" and "view" for the interface which will handle the button presses and model changes accordingly.  Here is what it will look like:

Notice that the ID and Balance are "greyed out".  This indicates that they are disabled and cannot be changed.
Here is the code:

Notice: Here is a final piece of code that can be used to test the whole thing:



 5.4  Standard Dialog Boxes


There are many commonly used dialog boxes.  These are as follows: Java has a class called JOptionPane that can bring up one of these standard dialog boxes.  There are many parameters and Java allows you to be very flexible in the way that you use them.  For instance, there are standard icons that are displayed on these dialog boxes, but you can make your own.

When using a dialog box, you get to specify:

Instead of describing all the options and all combinations here, I've decided to just give you templates that you can use.   Here is some code that tests many kinds of dialog boxes.  It brings up an interface with 9 buttons that allow you to check out the boxes.  The interface looks like this:

Here are the dialog boxes that will appear.

Plain Message Box: 

Information Message Box: 

Error Message Box: 

Information Message Box: 

Confirmation Dialog Box: 

Confirmation Dialog Box with Cancel: 

Select Option Dialog Box: 

Input Dialog Box: 

Option Dialog Box: 
 

Here is the code:
 

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

// Dialog Box Test Program
public class StandardDialogTester extends JFrame implements ActionListener {
    public StandardDialogTester (String title) {
        super(title);
        getContentPane().setLayout(new GridLayout(3, 3));

        JButton aButton = new JButton("Plain Message Box");
        getContentPane().add(aButton);
        aButton.addActionListener(this);

        aButton = new JButton("Warning Message Box");
        getContentPane().add(aButton);
        aButton.addActionListener(this);

        aButton = new JButton("Error Message Box");
        getContentPane().add(aButton);
        aButton.addActionListener(this);

        aButton = new JButton("Information Message Box");
        getContentPane().add(aButton);
        aButton.addActionListener(this);

        aButton = new JButton("Confirmation Dialog Box");
        getContentPane().add(aButton);
        aButton.addActionListener(this);

        aButton = new JButton("Confirmation Dialog Box with Cancel");
        getContentPane().add(aButton);
        aButton.addActionListener(this);

        aButton = new JButton("Multiple Option Dialog Box");
        getContentPane().add(aButton);
        aButton.addActionListener(this);

        aButton = new JButton("Input Dialog Box");
        getContentPane().add(aButton);
        aButton.addActionListener(this);

        aButton = new JButton("Chooser Dialog Box");
        getContentPane().add(aButton);
        aButton.addActionListener(this);
    }

    public void actionPerformed(ActionEvent e) {
        if (e.getActionCommand().equals("Plain Message Box")) {
            JOptionPane.showMessageDialog(this, "This is a plain message !!!",
                                        "Read This", JOptionPane.PLAIN_MESSAGE);
        }
        else if (e.getActionCommand().equals("Warning Message Box")) {
            JOptionPane.showMessageDialog(this, "Don't eat yellow snow.", "Warning",
                                      JOptionPane.WARNING_MESSAGE);
        }
        else if (e.getActionCommand().equals("Error Message Box")) {
            JOptionPane.showMessageDialog(this,
                  "Your program has stopped working !", "Error",
                    JOptionPane.ERROR_MESSAGE);
        }
        else if (e.getActionCommand().equals("Information Message Box")) {
            JOptionPane.showMessageDialog(this, "You better pass the final exam " +
              "or else...", "Information", JOptionPane.INFORMATION_MESSAGE);
        }
        else if (e.getActionCommand().equals("Confirmation Dialog Box")) {
           int result = JOptionPane.showConfirmDialog(this, "Do you want me to erase "
                + "your hard drive ?", "Answer this Question",
                JOptionPane.YES_NO_OPTION);
           if (result == 0)
                System.out.println("OK, I'm erasing it now ...");
           else
                System.out.println("Fine then, you clean it up!");
        }
        else if (e.getActionCommand().equals("Confirmation Dialog Box with Cancel")) {
           int result = JOptionPane.showConfirmDialog(this, "Do you want to " +
                      "overwrite the file ?", "Answer this Question",
                        JOptionPane.YES_NO_CANCEL_OPTION);
           switch(result) {
           case 0: System.out.println("OK, but don't come crying to me once its gone");break;
           case 1: System.out.println("Well you should pick a new name then");break;
           case 2: System.out.println("OK, I'll ask you again later");break;
           }
        }
        else if (e.getActionCommand().equals("Multiple Option Dialog Box")) {
            Object[] options = { "Outstanding", "Excellent", "Good", "Fair", "Poor" };
           int result = JOptionPane.showOptionDialog(this, "What do you think of " +
                  "these notes ?", "Pick an Option", JOptionPane.DEFAULT_OPTION,
                    JOptionPane.QUESTION_MESSAGE, null, options, options[0]);
            System.out.print("So,...,you think the notes are " + options[result] + " ...");
           if (result < 3)
                System.out.println("Thank you!");
           else
                System.out.println("but I put a lot of work into them !");
        }
        else if (e.getActionCommand().equals("Input Dialog Box")) {
            String inputValue = JOptionPane.showInputDialog("Please input your name");
            System.out.println("Your name is " + inputValue);
        }
        else if (e.getActionCommand().equals("Chooser Dialog Box")) {
            Object[] options = { "Apple", "Orange", "Strawberry", "Bannana", "Cherry" };
            Object selectedValue = JOptionPane.showInputDialog(this,
                  "Choose your favorite fruit", "Fruit Information",
                    JOptionPane.INFORMATION_MESSAGE, null, options, options[1]);
            System.out.println(selectedValue + "s sure do taste yummy.");
        }
    }

    public static void main(String args[]) {
        StandardDialogTester frame =  new StandardDialogTester("Standard Dialog Tester");
        frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
        frame.pack(); //chooses reasonable window size based on component prefered sizes
        frame.setVisible(true);
    }
}

Notice when running the code the output that appears in the console.  You should be able to figure out how to get information easily from your dialog boxes from this example.


There is another useful standard dialog box in Java that is used for selecting files.  It is called a JFileChoser.

Here is what it looks like:

Here is some code that opens up a FileChoser dialog box and displays the filename (no path)  that the user selects.

JFileChooser chooser = new JFileChooser();
    int returnVal = chooser.showOpenDialog(this);

    if (returnVal == JFileChooser.APPROVE_OPTION) {
        System.out.println("You chose to open this file: " +
                            chooser.getSelectedFile().getName());
    }

There are more options available that allow you to set the filters and starting directories.  Take a look at the Swing API.
 


 5.5  E-mail Buddy Dialog Box Example


We give here an example application that shows the use of a dialog box.   Consider having a bunch of buddies that you send e-mail to.  You'd like to make a nice little electronic address book that you can store the buddy's names along with his/her e-mail addresses.  Perhaps you even want to categorize the buddies as being "hot" (i.e. you talk to them often), or not-so-hot.

What exactly is an e-mail buddy ?  Well we've decided what information is to be kept, so we can easily develop a model of an EmailBuddy as follows:

// This class represents a "buddy" whose email address is kept.
// An additional boolean indicates whether or not this is a
// friend that is "hot" (i.e. contacted often)
public class EmailBuddy {
    private String   name;
    private String   address;
    private boolean  onHotList;

    // Here are some constructors
    public EmailBuddy() {
        name = "";
        address = "";
        onHotList = false;
    }
    public EmailBuddy(String aName, String anAddress) {
        name = aName;
        address = anAddress;
        onHotList = false;
    }

    // Here are the get methods
    public String getName() { return name; }
    public String getAddress() { return address; }
    public boolean onHotList() { return onHotList; }

    // Here are the set methods
    public void setName(String newName) { name = newName; }
    public void setAddress(String newAddress) { address = newAddress; }
    public void onHotList(boolean onList) { onHotList = onList; }

    // The appearance of the buddy
    public String toString() {
        return(name);
    }
}

As can be seen, there is nothing difficult here ... just your standard "run-of-the-mill" model class.  However, this class along is not really the model since we will have many of these EmailBuddy objects.  So, we'll make a Vector of them when we make the interface.


The task now is to design a nice interface for the main application.  To start, we must decide what the interface should do.  Here is a possible interface: Assume that we have decided upon the following view for the interface:

Notice that the interface does not show the e-mail addresses in the list.  It would be kinda cluttered looking.  Perhaps we could have made a second list box or something that would show the e-mail addresses.  Here is a good exercise: make a JTextField just beneath the list that will show the e-mail address of the currently selected Buddy in the list.  This is not hard to do.  Nevertheless, it is not necessary for the purposes of explaining this dialog box example.

How can we build the view for this interface ?  We'll start with a JPanel. We will use GridBagLayout to allow nice resizing.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

// This is the Panel that contains represents the view of the
// Email buddy application.
public class EmailBuddyPanel extends JPanel {

    private JButton   addButton;
    private JButton   removeButton;
    private JList     buddyList;
    private JCheckBox hotListButton;

    // These are the get methods that are used to access the components
    public JButton getAddButton() { return addButton; }
    public JButton getRemoveButton() { return removeButton; }
    public JCheckBox getHotListButton() { return hotListButton; }
    public JList getBuddyList() { return buddyList; }

    // This is the default constructor
    public EmailBuddyPanel(){
        super();

        // Use a GridBagLayout (lotsa fun)
        GridBagLayout layout = new GridBagLayout();
        GridBagConstraints layoutConstraints = new GridBagConstraints();
        setLayout(layout);

        // Add the buddy list
        buddyList = new JList();
        buddyList.setPrototypeCellValue("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
        JScrollPane scrollPane = new JScrollPane( buddyList,
        ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
        ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        layoutConstraints.gridx = 0;
        layoutConstraints.gridy = 0;
        layoutConstraints.gridwidth = 3;
        layoutConstraints.gridheight = 5;
        layoutConstraints.fill = GridBagConstraints.BOTH;
        layoutConstraints.insets = new Insets(10, 10, 10, 10);
        layoutConstraints.anchor = GridBagConstraints.NORTHWEST;
        layoutConstraints.weightx = 1.0;
        layoutConstraints.weighty = 1.0;
        layout.setConstraints(scrollPane, layoutConstraints);
        add(scrollPane);

        // Add the Add button
        addButton = new JButton("Add");
        layoutConstraints.gridx = 3;
        layoutConstraints.gridy = 0;
        layoutConstraints.gridwidth = 1;
        layoutConstraints.gridheight = 1;
        layoutConstraints.fill = GridBagConstraints.BOTH;
        layoutConstraints.insets = new Insets(10, 10, 10, 10);
        layoutConstraints.anchor = GridBagConstraints.EAST;
        layoutConstraints.weightx = 0.0;
        layoutConstraints.weighty = 0.0;
        layout.setConstraints(addButton, layoutConstraints);
        add(addButton);

        // Add the Remove button
        removeButton = new JButton("Remove");
        layoutConstraints.gridx = 3;
        layoutConstraints.gridy = 1;
        layoutConstraints.gridwidth = 1;
        layoutConstraints.gridheight = 1;
        layoutConstraints.fill = GridBagConstraints.BOTH;
        layoutConstraints.insets = new Insets(10, 10, 10, 10);
        layoutConstraints.anchor = GridBagConstraints.EAST;
        layoutConstraints.weightx = 0.0;
        layoutConstraints.weighty = 0.0;
        layout.setConstraints(removeButton, layoutConstraints);
        add(removeButton);

        // Add the ShowHotList button
        hotListButton = new JCheckBox("Show Hot List");
        layoutConstraints.gridx = 3;
        layoutConstraints.gridy = 3;
        layoutConstraints.gridwidth = 1;
        layoutConstraints.gridheight = 1;
        layoutConstraints.fill = GridBagConstraints.BOTH;
        layoutConstraints.insets = new Insets(10, 10, 10, 10);
        layoutConstraints.anchor = GridBagConstraints.EAST;
        layoutConstraints.weightx = 0.0;
        layoutConstraints.weighty = 0.0;
        layout.setConstraints(hotListButton, layoutConstraints);
        add(hotListButton);
    }
}

Notice that there is nothing really new here either.  This is just like a review.  We did however, make some get methods for the components so that we can access them from outside this class.



Now for the actual dialog box.  Ask yourself these questions:
  1. What causes the dialog box to appear ?
  2. What is the purpose of the dialog box ?
The dialog box should appear when the user attempts to add a Buddy.  It is used to enter information details about a particular buddy.  If we "play our cards just right", we'll be able to use the same dialog box to allow an "already existing" Buddy to have his/her details changed.

Here are some more questions that need to be answered:

Here are the answers:
  1. The dialog box should show all information about a particular Buddy.  This includes name, address and hot list status.
  2. The user should be able to change all 3 pieces of information about the buddy
  3. We should call it something like "Buddy Details" or "Buddy Information"
  4. Lay it out nicely.  Here's an idea:


Don't forget that we needed to add the OK and CANCEL buttons as well.  Also, there is no need to be able to resize the dialog box so we can just disable the resizing.

Here is a method that will be called from our dialog class to add the components to the dialog box.  It will take as parameters the container (i.e. from a call to getContentPane()) and an EmailBuddy object.   We pass in the container so that all components are added to it.  Can you figure out why we'd pass in a Buddy ?  Well, when the dialog box opens, we'll want to have some values appearing in the text fields indicating the Buddy's information.  This parameter will represent the model to which the dialog box affects.

    // This code adds the necessary components to the interface
    private void buildDialogWindow(Container aContainer, EmailBuddy aBuddy) {
        // Use no layout
        aContainer.setLayout(null);

        // Add the name label
        aLabel = new JLabel("Name:");
        aLabel.setLocation(10,10);
        aLabel.setSize(80, 30);
        aContainer.add(aLabel);

        // Add the name field
        nameField = new JTextField(aBuddy.getName());
        nameField.setLocation(110, 10);
        nameField.setSize(400, 30);
        aContainer.add(nameField);

        // Add the address label
        aLabel = new JLabel("Address:");
        aLabel.setHorizontalAlignment(JLabel.LEFT);
        aLabel.setLocation(10,50);
        aLabel.setSize(80, 30);
        aContainer.add(aLabel);

        // Add the address field
        addressField = new JTextField(aBuddy.getAddress());
        addressField.setLocation(110, 50);
        addressField.setSize(400, 30);
        aContainer.add(addressField);

        // Add the onHotList button
        hotListButton = new JCheckBox("On Hot List");
        hotListButton.setSelected(aBuddy.onHotList());
        hotListButton.setLocation(110, 100);
        hotListButton.setSize(120, 30);
        aContainer.add(hotListButton);

        // Add the Ok button
        okButton = new JButton("Ok");
        okButton.setLocation(300, 130);
        okButton.setSize(100, 40);
        aContainer.add(okButton);

        // Add the Cancel button
        cancelButton = new JButton("Cancel");
        cancelButton.setLocation(410, 130);
        cancelButton.setSize(100, 40);
        aContainer.add(cancelButton);
    }

We'll now look at the code needed to create the dialog box and get its behaviour working correctly.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;

public class BuddyDetailsDialo extends JDialog {

    // This is a pointer to the email buddy that is being edited
    private EmailBuddy aBuddy;

    // This is the client that is informed when the dialog box is closed
    private DialogClientInterface client;

    // These are the components of the dialog box
    private JLabel        aLabel;
    private JTextField    nameField;
    private JTextField    addressField;
    private JCheckBox     hotListButton;
    private JButton       okButton;
    private JButton       cancelButton;

    public BuddyDetailsDialog(Frame owner, String title, boolean modal,
                              EmailBuddy bud, DialogClientInterface cli){
        super(owner,title,modal);

        // Store these parameters into the instance variables
        client = cli;
        aBuddy = bud;

        // Put all the components onto the window and given them initial values
        buildDialogWindow(getContentPane(), aBuddy);

        // Add listeners for the Ok and Cancel buttons as well as window closing
        okButton.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent event){
                    okButtonClicked();
                }
            }
        );

        cancelButton.addActionListener(
            new ActionListener() {
                public void actionPerformed(ActionEvent event){
                    cancelButtonClicked();
                }
            }
        );

        addWindowListener(
            new WindowAdapter() {
                public void windowClosing(WindowEvent event) {
                    cancelButtonClicked();
                }
            }
        );

        // Set the size of the window
        setSize(526, 214);
    }

    // This code adds the necessary components to the interface
    private void buildDialogWindow(Container aContainer, EmailBuddy aBuddy) {
        // This code is given above
    }

    private void okButtonClicked(){
        aBuddy.setName(nameField.getText());
        aBuddy.setAddress(addressField.getText());
        aBuddy.onHotList(hotListButton.isSelected());
        if (client != null)
            client.dialogFinished(this);
        dispose();
    }

    private void cancelButtonClicked(){
        if (client != null)
            client.dialogCancelled(this);
        dispose();
    }
}

Once again, we see that we just add listeners for the OK and CANCEL buttons as well as the window closing event.  Then we merely make methods that are called for each.

Notice that when the ok button is clicked, the 3 pieces of changed buddy data are stored in the model buddy so that the buddy will have been altered by this dialog box.  Then we inform the client that OK was pressed.  For the cancel button, there is no work to do, just informing the client that CANCEL was pressed.



We're not done yet !  Now we need to work on the actual application that will be calling the dialog box.

We'll call the class  EmailBuddyApp and it will extend JFrame.  It will be the class that opens the dialog box and so it must implement the DialogClientInterface.   We'll need to store the buddies that we'll be making, so we make a vector as an instance variable.  We'll first make the application work such that we'll be able to add buddies to the list.  Here is the basic framework for the application:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.*;

public class EmailBuddyApp extends JFrame implements DialogClientInterface {
    // Store the model as a vector of email buddies
    private Vector      buddies;

    // Store the view that contains the components
    EmailBuddyPanel     view;

    // Here are the component listeners
    ActionListener      theAddButtonListener;

    // Here is the default constructor
    public EmailBuddyApp(String title){
        super(title);

        // Initially, no buddies
        buddies = new Vector();

        // Make a new viewing panel and add it to the pane
        view = new EmailBuddyPanel();
        getContentPane().add(view);

        // Make a listener for the add button
        theAddButtonListener = new ActionListener() {
           public void actionPerformed(ActionEvent event){
                addBuddy();
            }
        };
        // Start off with everything updated properly
        update();
    }

    // Enable all listeners
    private void enableListeners() {
        view.getAddButton().addActionListener(theAddButtonListener);
    }

    // Disable all listeners
    private void disableListeners() {
        view.getAddButton().removeActionListener(theAddButtonListener);
    }

    // This is called when the user clicks the add button
    private void addBuddy() {
        EmailBuddy  aBuddy = new EmailBuddy();

        // Add the buddy to the end of the Vector
        buddies.addElement(aBuddy);

        // Now bring up the dialog box
        BuddyDetailsDialog dialog = new BuddyDetailsDialog(null, "Buddy Details Dialog",
                                  true, aBuddy, this);
        dialog.setVisible(true);
    }

    // Called when the dialog box is closed with the Ok button
    public void dialogFinished(JDialog aDialog) {
        update();
    }

    // Called when the dialog box is closed with the cancel button or manually closed
    public void dialogCancelled(JDialog aDialog) {
        // Remove the latest buddy that was added if in add mode
        buddies.removeElement(buddies.lastElement());
    }

    // Update the list
    private void updateList() {
        // Update the list contents and select the last buddy
        view.getBuddyList().setListData(buddies);
        view.getBuddyList().setSelectedValue((EmailBuddy)buddies.lastElement(), true);
    }

    // Update the GUI
    private void update() {
        disableListeners();
        updateList();
        enableListeners();
    }

    // Code that starts the application
    public static void main(String args[]) {
        EmailBuddyApp frame =  new EmailBuddyApp("Email Buddy Application");
        frame.setSize(600,300);
        frame.setVisible(true);
    }
}

Perhaps the most interesting portions of the code are the addBuddy, dialogCancelled and updateList() methods.  When the user adds a buddy, we:

Since the dialog box is modal, nothing else happens until the dialog box is closed.  When closed, either the dialogFinished or dialogCancelled methods are called.  If the OK button was pressed, then dialogFinished is called and there is no work to be done except to update the screen.  This is because the dialog box already made the appropriate changes to the Buddy and we merely need to reflect the changes in the interface.  If dialogCancelled was called, then the user has cancelled the request to make changes and therefore we need to remove that buddy we added before the dialog box was openned.  We do not need to update anything however, since the interface appearance will not have changed.


Now ... what about the remove button ?  To get the remove button to work, we'll make some additions and changes.   What buddy gets removed ?  Probably the one that is currently selected from the list.  Here are the additions:         theRemoveButtonListener = new ActionListener() {
           public void actionPerformed(ActionEvent event){
                removeBuddy();
            }
        };

What about the hot list ?  Well we have to "hide" some of the buddies when it is on.  We will have to make a listener as well so that when the checkBox is toggled, the changes occur right away.   Here are the additions:         hotListListener = new ActionListener() {
           public void actionPerformed(ActionEvent event){
                toggleHotList();
            }
        };

What if we want to edit a buddy, not just add one ?  We will have to decide what action will cause the editing to take place.  One approach is to have the user double click on the buddy in the list and the dialog box will come up with that buddy's details within it.  We can then make changes to the data and close the dialog box.

To do this, notice that we currently have some small problems:

We can solve this problem by keeping a boolean flag which indicates whether or not we are in the midst of adding a buddy or whether or not we are editing.  Here are the changes:         doubleClickSelectionListener = new MouseAdapter() {
           public void mouseClicked(MouseEvent event){
           if (event.getClickCount() == 2)
                    editBuddy();
            }
        };         inAddMode = true; We're almost done now.  The remove button does not refresh properly.  That is, when nothing is selected, the remove button is diabled.  If we then make a selection in the list (i.e. single click), the button still remains disabled.  We should fix this.  Do you know how ?  Of course you do.  Just add an event handler for making list selections.  It just needs to call update() and the remove button will re-enable itself.

Here is the final code.  Notice that we've added a selectedBuddy instance variable which is used throughout.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.*;

public class EmailBuddyApp extends JFrame implements DialogClientInterface {
    // Store the model as a vector of email buddies
    private Vector      buddies;
    private EmailBuddy  selectedBuddy;
    private boolean     inAddMode;

    // Store the view that contains the components
    EmailBuddyPanel view;

    // Here are the component listeners
    ActionListener        theAddButtonListener;
    ActionListener        theRemoveButtonListener;
    ActionListener        hotListListener;
    ListSelectionListener buddyListSelectionListener;
    MouseListener         doubleClickSelectionListener;

    // Here is the default constructor
    public EmailBuddyApp(String title){
        super(title);

        buddies = new Vector();
        selectedBuddy = null;
        inAddMode = false;

        // Make a new viewing panel and add it to the pane
        view = new EmailBuddyPanel();
        getContentPane().add(view);

        // Make a listener for the add button
        theAddButtonListener = new ActionListener() {
           public void actionPerformed(ActionEvent event){
                addBuddy();
            }
        };

        // Make a listener for the revove button
        theRemoveButtonListener = new ActionListener() {
           public void actionPerformed(ActionEvent event){
                removeBuddy();
            }
        };

        // Make a listener for the hot list button
        hotListListener = new ActionListener() {
           public void actionPerformed(ActionEvent event){
                toggleHotList();
            }
        };

        // Make a listener to allow selection of buddies from the list
        buddyListSelectionListener = new ListSelectionListener() {
           public void valueChanged(ListSelectionEvent event){
               selectBuddy();
            }
        };

        // Make a listener to allow double click selections from the list for editing
        doubleClickSelectionListener = new MouseAdapter() {
           public void mouseClicked(MouseEvent event){
           if (event.getClickCount() == 2)
                    editBuddy();
            }
        };
        // Start off with everything updated properly
        update();
    }

    // Enable all listeners
    private void enableListeners() {
        view.getAddButton().addActionListener(theAddButtonListener);
        view.getRemoveButton().addActionListener(theRemoveButtonListener);
        view.getHotListButton().addActionListener(hotListListener);
        view.getBuddyList().addListSelectionListener(buddyListSelectionListener);
        view.getBuddyList().addMouseListener(doubleClickSelectionListener);
    }

    // Disable all listeners
    private void disableListeners() {
        view.getAddButton().removeActionListener(theAddButtonListener);
        view.getRemoveButton().removeActionListener(theRemoveButtonListener);
        view.getHotListButton().removeActionListener(hotListListener);
        view.getBuddyList().removeListSelectionListener(buddyListSelectionListener);
        view.getBuddyList().removeMouseListener(doubleClickSelectionListener);
    }

    // This is called when the user clicks the add button
    private void addBuddy() {
        EmailBuddy  aBuddy = new EmailBuddy();

        // Add the buddy to the end of the Vector
        buddies.add(aBuddy);
        selectedBuddy = aBuddy;
        inAddMode = true;

        // Now bring up the dialog box
        BuddyDetailsDialog dialog = new BuddyDetailsDialog(null, "Buddy Details Dialog",
                                  true, aBuddy, this);
        dialog.setVisible(true);
        //No need to call update() here since dialogFinished() calls it for us
    }

    // This is called when the user clicks the remove button
    private void removeBuddy() {
        // Remove the currently selected buddy from the list
        if (selectedBuddy != null) { //not needed since Remove Button is disabled when nobody is selected
            buddies.remove(selectedBuddy);
            update();
        }
    }

    // This is called when the user selects a buddy from the list
    private void selectBuddy() {
        selectedBuddy = (EmailBuddy)(view.getBuddyList().getSelectedValue());
        update();
    }

    // This is called when the user double clicks on an item in the list
    private void editBuddy() {
        // Now bring up the dialog box
        inAddMode = false;
        BuddyDetailsDialog dialog = new BuddyDetailsDialog(null, "Buddy Details Dialog",
                              true, selectedBuddy, this);
        dialog.setVisible(true);
        //No need to call update() here since dialogFinished() calls it for us
    }

    // This is called when the user clicks the hot list button
    private void toggleHotList() {
        update();
    }

    // Called when the dialog box is closed with the Ok button
    public void dialogFinished(JDialog aDialog) {
        update();
    }

    // Called when the dialog box is closed with the cancel button or manually closed
    public void dialogCancelled(JDialog aDialog) {
        if (inAddMode) {
            // Remove the latest buddy that was added if in add mode
            buddies.remove(buddies.lastElement());
            selectedBuddy = null;
        }
        inAddMode = false;
        update();  // Not really needed since nothing has changed
    }

    // Update the remove button
    private void updateRemove() {
        view.getRemoveButton().setEnabled(selectedBuddy != null);
    }

    // Update the list
    private void updateList() {
        boolean  foundSelected = false;

        // If the hot list is on, find all buddies that are on the hot list
        if (view.getHotListButton().isSelected()) {
            Vector temp = new Vector();

           for (int i=0; i<buddies.size(); i++) {
                EmailBuddy aBuddy = (EmailBuddy)buddies.get(i);
           if (aBuddy.onHotList()) {
                    temp.add(aBuddy);
             if (aBuddy == selectedBuddy)
                        foundSelected = true;
                }

            }
            view.getBuddyList().setListData(temp);
           if (!foundSelected)
                selectedBuddy = null;
        }
        else
            view.getBuddyList().setListData(buddies);

        if (selectedBuddy != null)
            view.getBuddyList().setSelectedValue(selectedBuddy, true);
    }

    // Update the GUI
    private void update() {
        disableListeners();
        updateList();
        updateRemove();
        enableListeners();
    }

    // Code that starts the application
    public static void main(String args[]) {
        EmailBuddyApp frame =  new EmailBuddyApp("Email Buddy Application");
        frame.setSize(600,300);
        frame.setVisible(true);
    }
}