Java Technology Home Page
A-Z Index

Java Developer Connection(SM)
Online Training

Downloads, APIs, Documentation
Java Developer Connection
Tutorials, Tech Articles, Training
Online Support
Community Discussion
News & Events from Everywhere
Products from Everywhere
How Java Technology is Used Worldwide
Print Button
 
Tutorial Index

AWT Fundamentals
Short Course

By jGuru

About This Short Course  Short Course  Exercises

Course Outline




Graphical User Interfaces

The JavaTM programming language provides a class library called the Abstract Window Toolkit (AWT) that contains a number of common graphical widgets. You can add these widgets to your display area and position them with a layout manager.

AWT Basics

All graphical user interface objects stem from a common superclass, Component. To create a Graphical User Interface (GUI), you add components to a Container object. Because a Container is also a Component, containers may be nested arbitrarily. Most often, you will use a Panel when creating nested GUIs.

Each AWT component uses native code to display itself on your screen. When you run a Java application under Microsoft Windows, buttons are really Microsoft Windows buttons. When you run the same application on a Macintosh, buttons are really Macintosh buttons. When you run on a UNIX machine that uses Motif, buttons are really Motif buttons.

Applications versus Applets

Recall that an Applet is a Java program that runs in a web page, while an application is one that runs from the command line. An Applet is a Panel that is automatically inserted into a web page. The browser displaying the web page instantiates and adds the Applet to the proper part of the web page. The browser tells the Applet when to create its GUI (by calling the init() method of Applet) and when to start() and stop() any special processing.

Applications run from a command prompt. When you execute an application from the command prompt, the interpreter starts by calling the application's main() method.

Basic GUI Logic

There are three steps you take to create any GUI application or applet:

  1. Compose your GUI by adding components to Container objects
  2. Setup event handlers to respond to user interaction with the GUI
  3. Display the GUI (automatically done for applets, you must explicitly do this for applications)

When you display an AWT GUI, the interpreter starts a new thread to watch for user interaction with the GUI. This new thread sits and waits until a user presses a key, clicks or moves the mouse, or any other system-level event that affects the GUI. When it receives such an event, it calls one of the event handlers you set up for the GUI. Note that the event handler code is executed within the thread that watches the GUI! (This is an import point that will be revisited later when events are reviewed.)

Because this extra thread exists, your main method can simply end after it displays the GUI. This makes GUI code very simple to write in AWT. Compose the GUI, setup event handlers, then display.

A Simple Example

The following simple example shows some GUI code. This example creates an Applet that contains just an Applet.

import java.awt.Button;
import java.applet.Applet;

public class AButton extends Applet {
  public void init() {
    // STEP 1: Compose the GUI
    Button beepButton = new Button("Beep"); 
    add(beepButton);

    // STEP 2: Setup Event handlers
    beepButton.addActionListener(new Beeper());

    // STEP 3: Display the GUI (automatic -- this is an applet)
  }
}

In step 2 from above, event handling is set up by adding an instance of a listener class to the button. When the button is pressed, a certain method in the listener class is called. In this example, the listener class implements ActionListener (because Button requires it). When the button is pressed, the button calls the actionPerformed() method of the listener class. Event handling is discussed in detail later in this module.

Suppose you want to produce a "beep" sound when the button is pressed. You can define your event handler as follows:

import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.Component;

public class Beeper implements ActionListener {
  public void actionPerformed(ActionEvent event) {
    Component c = (Component)event.getSource();
    c.getToolkit().beep();
  }
}

When actionPerformed() is called, it produces a beep sound on the computer (assuming your system is sound capable).

To try this applet, create a simple HTML page as follows.

<html>
  <applet code=AButton.class width=100 height=100>
  </applet>
</html>

Then test the HTML page by running appletviewer or by loading the HTML file in a browser that supports the Java Runtime Environment (JRE). Note that in this case, the browser must support at least version 1.1 of the JRE, as the example uses the event handling capabilities introduced with that release.

AWT Components

All AWT components extend class Component. Think of Component as the "root of all evil" for AWT. Having this single class is rather useful, as the library designers can put a lot of common code into it.

Next, examine each of the AWT components below. Most, but not all, directly extend Component. You've used most of the components should be familiar to you.

Buttons

A Button has a single line label and may be "pushed" with a mouse click.

import java.awt.*;
import java.applet.Applet;

public class ButtonTest extends Applet {
  public void init() {
    Button button = new Button("OK");
    add(button);
  }
}

Note that in the above example there is no event handling added; pressing the button will not do anything.

The AWT button has no direct support for images as labels.

Canvas

A Canvas is a graphical component representing a region where you can draw things such as rectangles, circles, and text strings. The name comes from a painter's canvas. You subclass Canvas to override its default paint() method to define your own components.

You can subclass Canvas to provide a custom graphic in an applet.

import java.awt.Canvas;
import java.awt.Graphics;

class DrawingRegion extends Canvas {
  public DrawingRegion() { 
    setSize(100, 50);
  }
  public void paint(Graphics g) {
    g.drawRect(0, 0, 99, 49); // draw border
    g.drawString("A Canvas", 20,20);
  }
}

Then you use it like any other component, adding it to a parent container, for example in an Applet subclass.

import java.applet.Applet;

public class CanvasPaintTest extends Applet {
  public void init() {
    DrawingRegion region = new DrawingRegion();
    add(region);
  }

The Canvas class is frequently extended to create new component types, for example image buttons. However, starting with the JRE 1.1, you can now directly subclass Component directly to create lightweight, transparent widgets.

Checkbox

A Checkbox is a label with a small pushbutton. The state of a Checkbox is either true (button is checked) or false (button not checked). The default initial state is false. Clicking a Checkbox toggles its state. For example:

import java.awt.*;
import java.applet.Applet;

public class CheckboxSimpleTest extends Applet {
  public void init() {
    Checkbox m = new Checkbox("Allow Mixed Case");
    add(m);
  }
}

To set a Checkbox initially true use an alternate constructor:

import java.awt.*;
import java.applet.Applet;

public class CheckboxSimpleTest2 extends Applet {
  public void init() {
    Checkbox m = new Checkbox("Label", true);
    add(m);
  }
}
CheckboxGroup

A CheckboxGroup is used to control the behavior of a group of Checkbox objects (each of which has a true or false state). Exactly one of the Checkbox objects is allowed to be true at one time. Checkbox objects controlled with a CheckboxGroup are usually referred to as "radio buttons".

The following example illustrates the basic idea behind radio buttons.

import java.awt.*;
import java.applet.Applet;

public class CheckboxGroupTest extends Applet {
  public void init() {
    // create button controller
    CheckboxGroup cbg = new CheckboxGroup();

    Checkbox cb1 = 
      new Checkbox("Show lowercase only", cbg, true);
    Checkbox cb2 =
      new Checkbox("Show uppercase only", cbg, false);

    add(cb1);
    add(cb2);
  }
}
Choice

Choice objects are drop-down lists. The visible label of the Choice object is the currently selected entry of the Choice.

import java.awt.*;
import java.applet.Applet;

public class ChoiceSimpleTest extends Applet {
  public void init() {
    Choice rgb = new Choice();

    rgb.add("Red");
    rgb.add("Green");
    rgb.add("Blue");

    add(rgb);
  }
}

The first item added is the initial selection.

Label

A Label is a displayed Label object. It is usually used to help indicate what other parts of the GUI do, such as the purpose of a neighboring text field.

import java.awt.*;
import java.applet.Applet;

public class LabelTest extends Applet {
  public void init() {
    add(new Label("A label"));
    // right justify next label
    add(new Label("Another label", Label.RIGHT));
  }
}

Like the Button component, a Label is restricted to a single line of text.

List

A List is a scrolling list box that allows you to select one or more items.

Multiple selections may be used by passing true as the second argument to the constructor.

import java.awt.*;
import java.applet.Applet;

public class ListSimpleTest extends Applet {
  public void init() {
    List list = new List(5, false);
    list.add("Seattle");
    list.add("Washington");
    list.add("New York");
    list.add("Chicago");
    list.add("Miami");
    list.add("San Jose");
    list.add("Denver");

    add(list);
  }
}

The constructor may contain a preferred number of lines to display. The current LayoutManager may choose to respect or ignore this request.

Scrollbar

A Scrollbar is a "slider" widget with characteristics specified by integer values that are set during Scrollbar construction. Both horizontal and vertical sliders are available.

import java.awt.*;
import java.applet.Applet;

// A simple example that makes a Scrollbar appear
public class ScrollbarSimpleTest extends Applet {
  public void init() {
    Scrollbar sb = 
      new Scrollbar(Scrollbar.HORIZONTAL,
                    0, // initial value is 0
                    5, // width of slider
                 -100, 105); // range -100 to 100
    add(sb);
  }
}

The maximum value of the Scrollbar is determined by subtracting the Scrollbar width from the maximum setting (last parameter).

TextField

A TextField is a scrollable text display object with one row of characters. The preferred width of the field may be specified during construction and an initial string may be specified.

import java.awt.*;
import java.applet.Applet;

public class TextFieldSimpleTest extends Applet {
  public void init() {
    TextField f1 =
      new TextField("type something");
    add(f1);
  }
}

Tips:

  • Call setEditable(true) to make the field read-only.
  • The constructor has an optional width parameter.
    This does not control the number of characters in the TextField, but is merely a suggestion of the preferred width on the screen. Note that layout managers may choose to respect or ignore this preferred width.

  • For password fields:
    field.setEchoChar('?');
    

    To clear/reset:

    field.setEchoChar((char)0);
    
TextArea

A TextArea is a multi-row text field that displays a single string of characters, where newline ('\n' or '\n\r' or '\r', depending on platform) ends each row. The width and height of the field is set at construction, but the text can be scrolled up/down and left/right.

import java.awt.*;
import java.applet.Applet;

public class TextAreaSimpleTest extends Applet {
  TextArea disp;
  public void init() {
    disp = new TextArea("Code goes here", 10, 30);
    add(disp);
  }
}

There is no way, for example, to put the cursor at beginning of row five, only to put the cursor at single dimension position 50.

There is a four-argument constructor that accepts a fourth parameter of a scrollbar policy. The different settings are the class constants: SCROLLBARS_BOTH, SCROLLBARS_HORIZONTAL_ONLY, SCROLLBARS_NONE, and SCROLLBARS_VERTICAL_ONLY. When the horizontal (bottom) scrollbar is not present, the text will wrap.

import java.awt.*;
import java.applet.Applet;

public class TextAreaScroll extends Applet {
  String s = 
    "This is a very long message " +
    "It should wrap when there is " +
    "no horizontal scrollbar.";
  public void init() {
    add(new TextArea (s, 4, 15, 
      TextArea.SCROLLBARS_NONE));
    add(new TextArea (s, 4, 15, 
      TextArea.SCROLLBARS_BOTH));
    add(new TextArea (s, 4, 15,
      TextArea.SCROLLBARS_HORIZONTAL_ONLY));
    add(new TextArea (s, 4, 15, 
      TextArea.SCROLLBARS_VERTICAL_ONLY));
  }
}
Common Component Methods

All AWT components share the 100-plus methods inherited from the Component class. Some of the most useful and commonly-used methods are listed below:

  • getSize() - Gets current size of component, as a Dimension.
    Dimension d = someComponent.getSize();
    int height = d.height;
    int width = d.width;
    

    Note: With the Java 2 Platform, you can directly access the width and height using the getWidth() and getHeight() methods. This is more efficient, as the component doesn't need to create a new Dimension object. For example:

    int height = someComponent.getHeight(); // Java 2 Platform only!
    int width  = someComponent.getWidth();  // Java 2 Platform only!
    

    If you're using the Java 2 platform, you should only use getSize() if you really need a Dimension object!

  • getLocation() - Gets position of component, relative to containing component, as a Point.
    Point p = someComponent.getLocation();
    int x = p.x;
    int y = p.y;
    

    Note: With the Java 2 Platform, you can directly access the x and y parts of the location using getX() and getY(). This is more efficient, as the component doesn't have to create a new Point object. For example:

    int x = someComponent.getX(); // Java 2 Platform only!
    int y = someComponent.getY(); // Java 2 Platform only!
    

    If you're using the Java 2 platform, you should only use getLocation() if you really need a Point object!

  • getLocationOnScreen() - Gets the position of the component relative to the upper-left corner of the computer screen, as a Point.
    Point p = someComponent.getLocationOnScreen();
    int x = p.x;
    int y = p.y;
    
  • getBounds() - Gets current bounding Rectangle of component.
    Rectangle r = someComponent.getBounds();
    int height = r.height;
    int width = r.width;
    int x = r.x;
    int y = r.y;
    

    This is like a combination of calling getLocation() and getSize(). Note: If you're using the Java 2 Platform and don't really need a Rectangle object, you should use getX(), getY(), getWidth(), and getHeight() instead.

  • setEnabled(boolean) - Toggles the state of the component. If set to true, the component will react to user input and appear normal. If set to false, the component will ignore user interaction, and usually appear ghosted or grayed-out.
  • setVisible(boolean) - Toggles the visibility state of the component. If set to true, the component will appear on the screen if it is contained in a visible container. If false, the component will not appear on the screen. Note that if a component is marked as not visible, any layout manager that is responsible for that component will usually proceed with the layout algorithm as though the component were not in the parent container! This means that making a component invisible will not simply make it disappear while reserving its space in the GUI. Making the component invisible will cause the layout of its sibling components to readjust!
  • setBackground(Color)/setForeground(Color) - Changes component background/foreground colors.
  • setFont(Font) - Changes font of text within component.

Containers

A Container is a Component, so may be nested. Class Panel is the most commonly-used Panel and can be extended to partition GUIs. Class Applet is a specialized Panel for running programs within a browser.

Common Container Methods

Besides the 100-plus methods inherited from the Component class, all Container subclasses inherit the behavior of about 50 common methods of Container (most of which just override a method of Component). While the most common method of Container used add(), has already been briefly discussed, if you need to access the list of components within a container, you may find the getComponentCount(), getComponents(), and getComponent(int) methods helpful.

ScrollPane

The ScrollPane container was introduced with the 1.1 release of the Java Runtime Environment (JRE) to provide a new Container with automatic scrolling of any one large Component. That large object could be anything from an image that is too big for the display area to a bunch of spreadsheet cells. All the event handling mechanisms for scrolling are managed for you. Also, there is no LayoutManager for a ScrollPane since there is only a single object within it.

The following example demonstrates the scrolling of a large image. Since an Image object is not a Component, the image must be drawn by a component such as a Canvas.

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

class ImageCanvas extends Component {
  private Image image;
  public ImageCanvas(Image i) {
    image = i;
  }
  public void paint(Graphics g) {
    if (image != null)
      g.drawImage(image, 0, 0, this);
  }
}

public class ScrollingImage extends Applet {
  public void init() {
    setLayout(new BorderLayout());
    ScrollPane sp =
      new ScrollPane(ScrollPane.SCROLLBARS_ALWAYS);
    Image im =
      getImage(getCodeBase(), "./images/SMarea.gif");
    sp.add(new ImageCanvas(im));
    add(sp, BorderLayout.CENTER);
  }
}

Event Handling

Events

Beginning with the 1.1 version of the JRE, objects register as listeners for events. If there are no listeners when an event happens, nothing happens. If there are twenty listeners registered, each is given an opportunity to process the event, in an undefined order. With a Button, for example, activating the button notifies any registered ActionListener objects. Consider SimpleButtonEvent applet which creates a Button instance and registers itself as the listener for the button's action events:

import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;

public class SimpleButtonEvent extends Applet
       implements ActionListener {
  private Button b;

  public void init() {
    b = new Button("Press me");
    b.addActionListener(this);
    add(b);
  }

  public void actionPerformed(ActionEvent e) {
    // If the target of the event was our Button
    // In this example, the check is not 
    //   truly necessary as we only listen to
    //   a single button
    if ( e.getSource() == b ) {
      getGraphics().drawString("OUCH",20,20);
    }
  }
}

Notice that any class can implement ActionListener, including, in this case, the applet itself. All listeners are always notified. If you don't want an event to be processed further, you can call the AWTEvent.consume() method. However each listener would then need to check for consumption using the isConsumed() method. Consuming events primarily stops events from being processed by the system, after every listener is notified. So, if you want to reject keyboard input from the user, you can consume() the KeyEvent. All the KeyListener implementers will still be notified, but the character will not be displayed. (Consumption only works for InputEvent and its subclasses.)

So, here is how everything works:

  • Components generate subclasses of AWTEvent when something interesting happens.
  • Event sources permit any class to be a listener using the addXXXListener() method, where XXX is the event type you can listen for, for example addActionListener(). You can also remove listeners using the removeXXXListener() methods. If there is an add/removeXXXListener() pair, then the component is a source for the event when the appropriate action happens.
  • In order to be an event handler you have to implement the listener type, otherwise, you cannot be added, ActionListener being one such type.
  • Some listener types are special and require you to implement multiple methods. For instance, if you are interested in key events, and register a KeyListener, you have to implement three methods, one for key press, one for key release, and one for both, key typed. If you only care about key typed events, it doesn't make sense to have to stub out the other two methods. There are special classes out there called adapters that implement the listener interfaces and stub out all the methods. Then, you only need to subclass the adapter and override the necessary method(s).
AWTEvent

Events subclass the AWTEvent class. And nearly every event-type has an associated Listener interface, PaintEvent and InputEvent do not. (With PaintEvent, you just override paint() and update(), for InputEvent, you listen for subclass events, since it is abstract.

Low-level Events

Low-level events represent a low-level input or window operation, like a key press, mouse movement, or window opening. The following table displays the different low-level events, and the operations that generate each event (each operation corresponds to a method of the listener interface):

ComponentEvent Hiding, moving, resizing, showing
ContainerEvent Adding/removing component
FocusEvent Getting/losing focus
KeyEvent Pressing, releasing, or typing (both) a key
MouseEvent Clicking, dragging, entering, exiting, moving, pressing, or releasing
WindowEvent Iconifying, deiconifying, opening, closing, really closed, activating, deactivating

For instance, typing the letter 'A' on the keyboard generates three events, one for pressing, one for releasing, and one for typing. Depending upon your interests, you can do something for any of the three events.

Semantic Events

Semantic events represent interaction with a GUI component; for instance selecting a button, or changing the text of a text field. Which components generate which events is shown in the next section.

ActionEvent Do the command
AdjustmentEvent Value adjusted
ItemEvent State changed
TextEvent Text changed
Event Sources

The following table represents the different event sources. Keep in mind the object hierarchy. For instance, when Component is an event source for something, so are all its subclasses:

Low-Level Events
Component ComponentListener
FocusListener
KeyListener
MouseListener
MouseMotionListener
Container ContainerListener
Window WindowListener

Semantic Events
Button
List
MenuItem
TextField
ActionListener
Choice
Checkbox
CheckboxMenuItem
List
ItemListener
Scrollbar AdjustmentListener
TextArea
TextField
TextListener

Notice that although there is only one MouseEvent class, the listeners are spread across two interfaces. This is for performance issues. Since motion mouse events are generated more frequently, if you have no interest in them, you can ignore them more easily, without the performance hit.

Event Listeners

Each listener interface is paired with one event type and contains a method for each type of event the event class embodies. For instance, the KeyListener contains three methods, one for each type of event that the KeyEvent has: keyPressed(), keyReleased(), and keyTyped().

Summary of Listener interfaces and their methods

Interface Method(s)
ActionListener actionPerformed(ActionEvent e)
AdjustmentListener adjustmentValueChanged(AdjustmentEvent e)
ComponentListener componentHidden(ComponentEvent e)
componentMoved(ComponentEvent e)
componentResized(ComponentEvent e)
componentShown(ComponentEvent e)
ContainerListener componentAdded(ContainerEvent e)
componentRemoved(ContainerEvent e)
FocusListener focusGained(FocusEvent e)
focusLost(FocusEvent e)
ItemListener itemStateChanged(ItemEvent e)
KeyListener keyPressed(KeyEvent e)
keyReleased(KeyEvent e)
keyTyped(KeyEvent e)
MouseListener mouseClicked(MouseEvent e)
mouseEntered(MouseEvent e)
mouseExited(MouseEvent e)
mousePressed(MouseEvent e)
mouseReleased(MouseEvent e)
MouseMotionListener mouseDragged(MouseEvent e)
mouseMoved(MouseEvent e)
TextListener textValueChanged(TextEvent e)
WindowListener windowActivated(WindowEvent e)
windowClosed(WindowEvent e)
windowClosing(WindowEvent e)
windowDeactivated(WindowEvent e)
windowDeiconified(WindowEvent e)
windowIconified(WindowEvent e)
windowOpened(WindowEvent e)
Event Adapters

Since the low-level event listeners have multiple methods to implement, there are event adapter classes to ease the pain. Instead of implementing the interface and stubbing out the methods you do not care about, you can subclass the appropriate adapter class and just override the one or two methods you are interested in. Since the semantic listeners only contain one method to implement, there is no need for adapter classes.

public class MyKeyAdapter extends KeyAdapter {
  public void keyTyped(KeyEvent e) {
    System.out.println("User typed: " +
      KeyEvent.getKeyText(e.getKeyCode()));
  }
}
Button Pressing Example

The following code demonstrates the basic concept a little more beyond the earlier example. There are three buttons within a Frame, their displayed labels may be internationalized so you need to preserve their purpose within a command associated with the button. Based upon which button is pressed, a different action occurs.

import java.awt.*;
import java.awt.event.*;

public class Activator {
  public static void main(String[] args) {
    Button b;
    ActionListener al = new MyActionListener();
    Frame f = new Frame("Hello Java");
    f.add(b = new Button("Hola"), BorderLayout.NORTH);
    b.setActionCommand("Hello");
    b.addActionListener(al);
    f.add(b = new Button("Aloha"), BorderLayout.CENTER);
    b.addActionListener(al);
    f.add(b = new Button("Adios"), BorderLayout.SOUTH);
    b.setActionCommand("Quit");
    b.addActionListener(al);
    f.pack();
    f.show();
  }
}

class MyActionListener implements ActionListener {
  public void actionPerformed(ActionEvent e) {
    // Action Command is not necessarily label
    String s = e.getActionCommand();
    if (s.equals("Quit")) {
      System.exit(0);
    }
    else if (s.equals("Hello")) {
      System.out.println("Bon Jour");
    }
    else {
      System.out.println(s + " selected");
    }
  }
}

Since this is an application, you need to save the source (as Activator.java), compile it, and run it outside the browser. Also, if you wanted to avoid checking which button was selected, you can associate a different ActionListener to each button, instead of one to all. This is actually how many Integrated Development Environments (IDEs) generate their code.

Adapters Example

The following code demonstrates using an adapter as an anonymous inner class to draw a rectangle within an applet. The mouse press signifies the top left corner to draw, with the mouse release the bottom right.

import java.awt.*;
import java.awt.event.*;

public class Draw extends java.applet.Applet {
  public void init() {
    addMouseListener(
        new MouseAdapter() {
            int savedX, savedY;
            public void mousePressed(MouseEvent e) {
              savedX = e.getX();
              savedY = e.getY();
            }
            public void mouseReleased(MouseEvent e) {
              Graphics g = Draw.this.getGraphics();
              g.drawRect(savedX, savedY, 
                         e.getX()-savedX,
                         e.getY()-savedY);
            }
        }
    );
  }
}

Applications and Menus

GUI-based Applications

To create a window for your application, define a subclass of Frame (a Window with a title, menubar, and border) and have the main method construct an instance of that class.

Applications respond to events in the same way as applets do. The following example, BasicApplication, responds to the native window toolkit quit, or closing, operation:

import java.awt.*;
import java.awt.event.*;

public class BasicApplication extends Frame {
  public BasicApplication() {
    super("BasicApplication Title");
    setSize(200, 200);
    // add a demo component to this frame
    add(new Label("Application Template...", Label.CENTER),
      BorderLayout.CENTER);
    addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        setVisible(false); dispose();
        System.exit(0);
      }
    });
  }

  public static void main(String[] args) {
    BasicApplication app = new BasicApplication();
    app.setVisible(true);
  }
}

Consider an application that displays the x,y location of the last mouse click and provides a button to reset the displayed x,y coordinates to 0,0:

import java.awt.*;
import java.awt.event.*;
public class CursorFrame extends Frame {
  TextField a, b;
  Button btn;
  public CursorFrame() {
    super("CursorFrame");
    setSize(400, 200);
    setLayout(new FlowLayout());
    add(new Label("Click the mouse..."));
    a = new TextField("0", 4);
    b = new TextField("0", 4);
    btn = new Button("RESET");
    add(a); add(b); add(btn);
    addMouseListener(new MouseAdapter() {
      public void mousePressed(MouseEvent e) {
        a.setText(String.valueOf(e.getX()));
        b.setText(String.valueOf(e.getY()));
      }
    });
    addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        setVisible(false);
        dispose();
        System.exit(0);
      }
    });
    btn.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        a.setText("0");
        b.setText("0");
      }
    });
  }
  public static void main(String[] args) {
    CursorFrame app = new CursorFrame();
    app.setVisible(true);
  }
}

This application provides anonymous classes to handle mouse events, application window closing events, and the action event for resetting the text fields that report mouse coordinates.

When you have a very common operation, such as handling application window closing events, it often makes sense to abstract out this behavior and handle it elsewhere. In this case, it's logical to do this by extending the existing Frame class, creating the specialization AppFrame:

import java.awt.*;
import java.awt.event.*;

public class AppFrame extends Frame
    implements WindowListener {
  public AppFrame(String title) {
    super(title);
    addWindowListener(this);
  }
  public void windowClosing(WindowEvent e) {
    setVisible(false);
    dispose();
    System.exit(0);
  }
  public void windowClosed(WindowEvent e) {}
  public void windowDeactivated(WindowEvent e) {}
  public void windowActivated(WindowEvent e) {}
  public void windowDeiconified(WindowEvent e) {}
  public void windowIconified(WindowEvent e) {}
  public void windowOpened(WindowEvent e) {}
}

AppFrame directly implements WindowListener, providing empty methods for all but one window event, namely, the window closing operation. With this definition, applications such as CursorFrame can extend AppFrame instead of Frame and avoid having to provide the anonymous class for window closing operations:

Exercises

  1. Displaying Files
  2. Converting an Applet to an Application
Applications: Dialog Boxes

A Dialog is a window that requires input from the user. Components may be added to the Dialog like any other container. Like a Frame, a Dialog is initially invisible. You must call the method setVisible() to activate the dialog box.

import java.awt.*;
import java.awt.event.*;

public class DialogFrame extends AppFrame {
  Dialog d;

  public DialogFrame() {
    super("DialogFrame");
    setSize(200, 100);
    Button btn, dbtn;
    add(btn = new Button("Press for Dialog Box"),
      BorderLayout.SOUTH);
    d = new Dialog(this, "Dialog Box", false);
    d.setSize(150, 150);
    d.add(new Label("This is the dialog box."),
      BorderLayout.CENTER);
    d.add(dbtn = new Button("OK"),
      BorderLayout.SOUTH);
    btn.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        d.setVisible(true);
      }
    });
    dbtn.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        d.setVisible(false);
      }
    });
    d.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        d.setVisible(false);
      }
    });
  }
  public static void main(String[] args) {
    DialogFrame app = new DialogFrame();
    app.setVisible(true);
  }
}

Again, you can define anonymous classes on the fly for:

  1. Activating the dialog window from the main application's command button.
  2. Deactivating the dialog window from the dialog's command button.
  3. Deactivating the dialog window in response to a native window system's closing operation.

Although the anonymous class functionality is quite elegant, it is inconvenient to have to repeatedly include the window-closing functionality for every dialog instance that your applications instantiate by coding and registering the anonymous window adapter class. As with AppFrame, you can define a specialization of Dialog that adds this functionality and thereafter simply use the enhanced class. For example, WMDialog provides this functionality:

import java.awt.*;
import java.awt.event.*;
public class WMDialog extends Dialog
    implements WindowListener {
  public WMDialog(Frame ref, String title, boolean modal) {
    super(ref, title, modal);
    addWindowListener(this);
  }
  public void windowClosing(WindowEvent e) {
    setVisible(false);
  }
  public void windowClosed(WindowEvent e) {}
  public void windowDeactivated(WindowEvent e) {}
  public void windowActivated(WindowEvent e) {}
  public void windowDeiconified(WindowEvent e) {}
  public void windowIconified(WindowEvent e) {}
  public void windowOpened(WindowEvent e) {}
}

Exercise

  1. OK Dialog
Applications: File Dialog Boxes

The utility class FileDialog is useful for getting file names from the application user. FileDialog.getFile() reports the name of the file selected by the user. If this returns null, the user decided to cancel the selection. Currently, usage of FileDialog is limited to applications and trusted applets.

Exercise

  1. Display a File from FileDialog
Applications: Menus

An application can have a MenuBar object containing Menu objects that are comprised of MenuItem objects. Each MenuItem can be a string, menu, checkbox, or separator (a line across the menu).

To add menus to any Frame or subclass of Frame:

  1. Create a MenuBar
    MenuBar mb = new MenuBar();
    
  2. Create a Menu
    Menu m = new Menu("File");
    
  3. Create your MenuItem choices and add each to the Menu, in the order you want them to appear, from top to bottom.
    m.add(new MenuItem("Open"));
    m.addSeparator();     // add a separator
    m.add(new CheckboxMenuItem("Allow writing"));
    // Create submenu
    Menu sub = new Menu("Options...");
    sub.add(new MenuItem("Option 1"));
    m.add(sub);           // add sub to File menu
    
  4. Add each Menu to the MenuBar in the order you want them to appear, from left to right.
    mb.add(m);            // add File menu to bar
    
  5. Add the MenuBar to the Frame by calling the setMenuBar() method .
    setMenuBar(mb); // set menu bar of your Frame
    

The following program, MainWindow, creates an application window with a menu bar and several menus using the strategy outlined above:

import java.awt.*;
import java.awt.event.*;

// Make a main window with two top-level menus: File and Help.
// Help has a submenu and demonstrates a few interesting menu items.
public class MainWindow extends Frame {
  public MainWindow() {
    super("Menu System Test Window");
    setSize(200, 200);

    // make a top level File menu
    FileMenu fileMenu = new FileMenu(this);

    // make a top level Help menu
    HelpMenu helpMenu = new HelpMenu(this);

    // make a menu bar for this frame 
    // and add top level menus File and Menu
    MenuBar mb = new MenuBar();
    mb.add(fileMenu);
    mb.add(helpMenu);
    setMenuBar(mb);
    addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        exit();
      }
    });
  }

  public void exit() {
    setVisible(false); // hide the Frame
    dispose(); // tell windowing system to free resources
    System.exit(0); // exit
  }

  public static void main(String args[]) {
    MainWindow w = new MainWindow();
    w.setVisible(true);
  }
}

// Encapsulate the look and behavior of the File menu
class FileMenu extends Menu implements ActionListener {
  MainWindow mw;  // who owns us?
  public FileMenu(MainWindow m) {
    super("File");
    mw = m;
    MenuItem mi;
    add(mi = new MenuItem("Open"));
    mi.addActionListener(this);
    add(mi = new MenuItem("Close"));
    mi.addActionListener(this);
    add(mi = new MenuItem("Exit"));
    mi.addActionListener(this);
  }
  // respond to the Exit menu choice
  public void actionPerformed(ActionEvent e) {
    String item = e.getActionCommand();
    if (item.equals("Exit")) 
      mw.exit();
    else 
      System.out.println("Selected FileMenu " + item);
  }
}

// Encapsulate the look and behavior of the Help menu
class HelpMenu extends Menu implements ActionListener {
  MainWindow mw;  // who owns us?
  public HelpMenu(MainWindow m) {
    super("Help");
    mw = m;
    MenuItem mi;
    add(mi = new MenuItem("Fundamentals"));
    mi.addActionListener(this);
    add(mi = new MenuItem("Advanced"));
    mi.addActionListener(this);
    addSeparator();
    add(mi = new CheckboxMenuItem("Have Read The Manual"));
    mi.addActionListener(this);
    add(mi = new CheckboxMenuItem("Have Not Read The Manual"));
    mi.addActionListener(this);

    // make a Misc sub menu of Help menu
    Menu subMenu = new Menu("Misc");
    subMenu.add(mi = new MenuItem("Help!!!"));
    mi.addActionListener(this);
    subMenu.add(mi = new MenuItem("Why did that happen?"));
    mi.addActionListener(this);
    add(subMenu);
  }
  // respond to a few menu items
  public void actionPerformed(ActionEvent e) {
    String item = e.getActionCommand();
    if (item.equals("Fundamentals"))
      System.out.println("Fundamentals");
    else if (item.equals("Help!!!")) 
      System.out.println("Help!!!");
    // etc...
  }
}

Exercise

  1. Menus
Menu Shortcuts

One nice feature of the MenuItem class is its ability to provide menu shortcuts or speed keys. For instance, in most applications that provide printing capabilities, pressing Ctrl-P initiates the printing process. When you create a MenuItem you can specify the shortcut associated with it. If the user happens to press the speed key, the action event is triggered for the menu item.

If you want to create two menu items with speed keys, Ctrl-P for Print and Shift-Ctrl-P for Print Preview, the following code would do that:

file.add (mi = new MenuItem ("Print",
    new MenuShortcut('p')));
file.add (mi = new MenuItem ("Print Preview",
    new MenuShortcut('p', true)));

The example above uses Ctrl-P and Shift-Ctrl-P shortcuts on Windows/Motif. The use of Ctrl for the shortcut key is defined by the Toolkit method getMenuShortcutKeyMask(). For the Macintosh, this would be the Command key. An optional boolean parameter to the constructor determines the need for the Shift key appropriate to the platform.

Pop-up Menus

One restriction of the Menu class is that it can only be added to a Frame. If you want a menu in an Applet, you are out of luck (unless you use the Swing component set). While not necessarily a perfect solution, you can associate a pop-up menu with any Component, of which Applet is a subclass. A PopupMenu is similar to a Menu in that it holds MenuItem objects. However, instead of appearing at the top of a Frame, you pop the popup menu up over any component, usually when the user generates the appropriate mouse event.

The actual mouse interaction to generate the event is platform specific so there is the means to determine if a MouseEvent triggers the pop-up menu via the MouseEvent.isPopupTrigger() method. It is then your responsibility to position and display the PopupMenu.

The following program, PopupApplication, demonstrates this portable triggering of a pop-up menu, as well as activating a pop-up menu from a command button:

import java.awt.*;
import java.awt.event.*;
public class PopupApplication extends AppFrame {
  Button btn; TextField msg; PopupAppMenu m;
  public PopupApplication() {
    super("PopupApplication");
    setSize(200, 200);
    btn = new Button("Press for pop-up menu...");
    add(btn, BorderLayout.NORTH);
    msg = new TextField();
    msg.setEditable(false);
    add(msg, BorderLayout.SOUTH);
    m = new PopupAppMenu(this);
    add(m);
    btn.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        m.show(btn, 10, 10);
      }
    });
    addMouseListener(new MouseAdapter() {
      public void mousePressed(MouseEvent e) {
        if (e.isPopupTrigger())
          m.show(e.getComponent(), e.getX(), e.getY());
      }
      public void mouseReleased(MouseEvent e) {
        if (e.isPopupTrigger())
          m.show(e.getComponent(), e.getX(), e.getY());
      }
    });
  }
  public static void main(String[] args) {
    PopupApplication app = new PopupApplication();
    app.setVisible(true);
  }
}

class PopupAppMenu extends PopupMenu
    implements ActionListener {
  PopupApplication ref;
  public PopupAppMenu(PopupApplication ref) {
    super("File");
    this.ref = ref;
    MenuItem mi;
    add(mi = new MenuItem("Copy"));
    mi.addActionListener(this);
    add(mi = new MenuItem("Cut"));
    mi.addActionListener(this);
    add(mi = new MenuItem("Paste"));
    mi.addActionListener(this);
  }
  public void actionPerformed(ActionEvent e) {
    String item = e.getActionCommand();
    ref.msg.setText("Selected menu item: " + item);
  }
}

Copyright 1996-2000 jGuru.com. All Rights Reserved.


Print Button
[ This page was updated: 15-Jul-2000 ]
Products & APIs | Developer Connection | Docs & Training | Online Support
Community Discussion | Industry News | Solutions Marketplace | Case Studies
Glossary - Applets - Tutorial - Employment - Business & Licensing - Java Store - Java in the Real World
FAQ | Feedback | Map | A-Z Index
For more information on Java technology
and other software from Sun Microsystems, call:
(800) 786-7638
Outside the U.S. and Canada, dial your country's AT&T Direct Access Number first.
Sun Microsystems, Inc.
Copyright © 1995-2000 Sun Microsystems, Inc.
All Rights Reserved. Terms of Use. Privacy Policy.