A6. AWT Programming


In this section, you will learn:

  • How to make widgets respond to physical events such as mouse clicks, key presses, or button pushes.
  • How to create windows and menus for stand-alone Java applications.

Events 1.0 Style

Event handling changed drastically between 1.0 and 1.1 versions of Java. Until the runtime world catches up, almost all applet-based programming will require you to create code that uses 1.0 style event handling (and it will work within a 1.1 environment). Until the millions of Netscape Navigator 2.0 and 3.0 users upgrade to a non-existent Java 1.1 version of the browser, your applets should use the 1.0 style event handling, and no features introduced with Java 1.1 (or you need to provide multiple versions of things). Applications that include the Java Runtime Extensions (JRE) are free to do everything with the 1.1-style, since they include the full runtime.

After a GUI has built an interface, it waits for an event such as a mouse click or a Button press to trigger an action. All Java Component objects except Label can be triggered into action by an event. When triggered, the Java Component object, including Container objects such as Panels and Applets, can either respond to an event itself or instead let the event be handled by the enclosing Container object, normally called the "parent". (Here, "parent" does not mean super.)

Consider the following applet example that overrides mouseDown():

import java.awt.*;
import java.applet.Applet;
public class SimpleEvent extends Applet {
  public boolean mouseDown(Event e,int x,int y){
  // upon mouse click, put "hi" at that location
    getGraphics().drawString("hi", x, y);
    return true; 
  // say that we handled this event
  }
}

We have trapped the mouseDown() event in the Applet subclass (which is indirectly a subclass of Container, Component, and Object). Also, notice that if you invalidate the screen it does not retain the previous screen. This is because we are writing to the screen directly with getGraphics() vs. drawing in the paint() routine, or using a separate buffer.

Event Flow

When an event occurs, a call is made to the native window toolkit method

Container.deliverEvent()

that determines which Component should be signaled with the event. When the appropriate Component is identified, the method

Component.postEvent()

delivers the event to the Component and invokes handleEvent().

Summary of Event Methods
Event MethodFunction
Container.deliverEventDetermine which Component gets the Event.
Component.postEventPost an Event to the Component.
Component.handleEventHandle the Event; call helper functions.

Event Handler Return Values

Each event handling method returns either true (if the method handled the event) or false (if the method did not handle the event [or did, but you still wants the parent to deal with it]). When handleEvent() returns false, the postEvent() and handleEvent() methods of the parent are called. In this way, non-handled events are passed from innermost to outermost containers. (The applet window is the outermost enclosing container.)

Convenience Functions

Method handleEvent() calls a number of methods termed convenience functions:

  • Mouse has moved over the component.
    boolean mouseEnter(Event e, int x, int y)
    
  • Mouse has left the component.
    boolean mouseExit(Event e, int x, int y)
    
  • Mouse has moved without button being down.
    boolean mouseMove(Event e, int x, int y)
    
  • Mouse button pushed.
    boolean mouseDown(Event e, int x, int y)
    
  • Mouse button is down and mouse moved.
    boolean mouseDrag(Event e, int x, int y)
    
  • Mouse button released.
    boolean mouseUp(Event e, int x, int y)
    
  • A key was pressed.
    boolean keyDown(Event e, int key)
    
  • A key was released.
    boolean keyUp(Event e, int key)
    
  • An action such as a Button push or List selection occurred.
    boolean action(Event e, Object arg)
    
  • Component has the input focus.
    boolean gotFocus(Event e, Object arg)
    
  • Component has lost the input focus.
    boolean lostFocus(Event e, Object arg)
    

You can customize the response to an event either by overriding the Component.handleEvent() method or overriding one of the convenience functions called by handleEvent().

Although all Component objects will respond to every event they receive, they do not automatically generate all events, in all environments. For example, TextField objects do not generate got/lost focus events on Microsoft Windows and TextArea objects do not generate key down events under Unix. This either requires you to program to the least common denominator or lose functionality when moving between run-time environments. For Internet-based projects, the least common denominator approach seems to be the best way to go. For intranet-based efforts, one can control the interface somewhat and program to that run-time specifically.

Action Events

Activating a graphical widget object such as a Button generally triggers the method

public boolean action(Event e, Object arg)

for that Component.

By default, event handlers for components return false. You must subclass the components to override action().

The Event object passed to action() has, among other things, a target (specifying which Component was activated) and an arg field (passed as the second argument). The event argument differs from target to target.

For example, the following applet responds to a Button press by drawing a string in the applet window.

import java.awt.*;
import java.applet.Applet;
public class SimpleButtonEvent extends Applet {
  Button b;
  public void init() {
    b = new Button("Press me");
    add(b);
  }
  public boolean action(Event e, Object arg) {
    // if the target of the event was our Button
    if ( e.target == b ) {
      getGraphics().drawString("OUCH",20,20);
      return true; // we've handled the event
    } else {
      // Didn't handle event, let parent
      // handle it. Here, there is no parent 
      // because the applet is the root window
      return false;
    }
  }
}

To further illustrate how events are passed from component to component, consider the following simple applet with two mouseDown event handlers -- one in a Canvas object and one in the applet.

import java.awt.*;
import java.applet.Applet;
// Play a sound upon any mouse click.
// If the mouse is in the bordered Canvas region
// display "Hi" ALSO. Cascading messages are used
// (i.e., the HiRegion responds to mouseDown and by
// returning false the applet
// responds to the SAME event.
public class PassMouseEvent extends Applet {
  HiRegion region;
  public void init() {
    resize(200,200);
    region = new HiRegion();
    add(region);
  }
  // upon mouse click, play a sound
  public boolean mouseDown(Event e, int x, int y) {
    play(getCodeBase(), "audio/beep.au");
    // handled event
    // don't have parent do anything
    return true;
  }
}

// A square Canvas with a border. 
// Behavior: puts "Hi" into Canvas for each mouse click.
class HiRegion extends Canvas {
  public HiRegion() { resize(100,100);}
  public void paint(Graphics g) {
    // draw a border around canvas
    g.drawRect(0,0,99,99);
  }
  public boolean mouseDown(Event e, int x, int y) {
    getGraphics().drawString("Hi", x, y);
    // pretend we did NOT handle this event.
    return false;
    // PassMouseEvent.mouseDown() will be called
  }
}

The Event Class

Whenever you have an instance of Event, you have access to its many instance variables. When dealing with convenience functions, their values are used as the additional parameters.

VariableDescription
argComponent specific argument. For instance, TextField is contents; Checkbox is state.
clickCountFor MOUSE_DOWN events, number of consecutive times mouse button pressed.
evtA means of dealing with multiple events as one linked list.
idEvent identifier. There are a series of constants in Event class to signify event type:
  • ACTION_EVENT
  • KEY_ACTION
  • KEY_ACTION_RELEASE
  • KEY_PRESS
  • KEY_RELEASE
  • MOUSE_DOWN
  • MOUSE_DRAG
  • MOUSE_ENTER
  • MOUSE_EXIT
  • MOUSE_MOVE
  • MOUSE_UP
  • LIST_DESELECT
  • LIST_SELECT
  • SCROLL_ABSOLUTE
  • SCROLL_LINE_DOWN
  • SCROLL_LINE_UP
  • SCROLL_PAGE_DOWN
  • SCROLL_PAGE_UP
  • WINDOW_DEICONIFY
  • WINDOW_DESTROY
  • WINDOW_EXPOSE
  • WINDOW_ICONIFY

If you override the convenience functions, you do not have to worry about them. If you deal with events in handleEvent(), you need to find out what event happened in order to process it properly.

keyFor keyboard events, the integer value of key pressed. There are some constants within the Event class for special keys:
  • F1, F2, ..., F12
  • HOME, END, PGUP, PGDN, UP, DOWN, LEFT, RIGHT
modifiersShows state of modifier keys (SHIFT, CTRL, ALT, META) when event happened. Check against masks for set:
  • ALT_MASK
  • CTRL_MASK
  • META_MASK
  • SHIFT_MASK
if ((e.modifiers & SHIFT_MASK) != 0) {
    System.out.println("Shift pressed");
}
targetSource of event
whenWhen event happened, as a long.
x, yCoordinates of where event happened, relative to origin of target.

Magercises

  • 1. Color List.
  • 2. Radio Buttons.
  • Events 1.1 Style

    With Java 1.1, instead of the system actively searching for someone to process an event, working its way down and out of the containment hierarchy, objects register as listeners for events. If there are no listeners, nothing happens. If there are twenty listeners registered, each is given an opportunity to process the event, in an undefined order. For example, with a Button, activating the button notifies any registered ActionListeners. Converting the SimpleButtonEvent example from before to 1.1 event handling might look something like this:

    import java.awt.*;
    import java.awt.event.*;
    import java.applet.Applet;
    public class SimpleButtonEvent11 extends Applet
        implements ActionListener {
      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, check not truly necessary.
        if ( e.getSource() == b ) {
          getGraphics().drawString("OUCH",20,20);
        }
      }
    }
    

    Notice that there is no boolean value returned and any class can implement ActionListener. 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 via the isConsumed method. Consuming events primarily stop events from being processed by the system, after each listener is notified. So, if you want to reject keyboard input from the user, you can consume the KeyEvent. All the KeyListeners will be notified, but the character will not be displayed. (Consumption only works for InputEvents.)

    So, here is how everything works:

    • Components generate subclasses of AWTEvent when something interesting happens.
    • Event sources permit any class to be a listener via an addXXXListener method, where XXX is the event type you can listen for, like addActionListener. You can also remove listeners via removeXXXListener methods. If there is an add/removeXXXListener pair, then you are 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

    All 1.1 style 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)

    ComponentEventhiding, moving, resizing, showing
    ContainerEventadding/removing component
    FocusEventgetting/losing focus
    KeyEventpressing, releasing, or typing (both) a key
    MouseEventclicking, dragging, entering, exiting, moving, pressing, or releasing
    WindowEventiconifying, 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 below.

    ActionEventDo the command
    AdjustmentEventValue adjusted
    ItemEventState changed
    TextEventText 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 children:

    Low-Level Events
    ComponentComponentListener
    FocusListener
    KeyListener
    MouseListener
    MouseMotionListener
    ContainerContainerListener
    WindowWindowListener

    Semantic Events
    Button
    List
    MenuItem
    TextField
    ActionListener
    Choice
    Checkbox
    CheckboxMenuItem
    List
    ItemListener
    ScrollbarAdjustmentListener
    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, 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, different actions occur.

    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"), "North");
        b.setActionCommand ("Hello");
        b.addActionListener (al);
        f.add (b=new Button ("Aloha"), "Center");
        b.addActionListener (al);
        f.add (b=new Button ("Adios"), "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, compile it, and run it outside the browser.

    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);
                           }
                         });
      }
    }
    

    If you happen to be running a 1.1 browser, you can try this out. Otherwise, you can save the source and try it with appletviewer.

    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.

    For example,

    import java.awt.*;
    
    // Having only the initialization in the 
    // main class allows you to reuse 
    // YourMainWindow more easily in other 
    // situations; YourMainWindow does not have to be 
    // the main program to be reused.
    public class BasicApplication {
      public static void main(String[] args) {
        YourMainWindow w = new YourMainWindow();
        w.show();
      }
    }
    class YourMainWindow extends Frame {
      public YourMainWindow() {
        super("YourMainWindow Title");
        resize(200,200);
        // add what you want to this Frame
        add("Center", new Label("Application Template..."));
      }
    }
    

    Your applications respond to events in the same way as your applets do. The BasicApplication example above can be modified to respond to the native window toolkit "quit" menu selection (as opposed to a Java menu item on a MenuBar):

    // handle the WINDOW events here
    public boolean handleEvent(Event e) {
      if( e.id == Event.WINDOW_DESTROY ) {
        hide(); // hide the Frame
        // tell windowing system that resources can be freed
        dispose();
        System.exit(0); // exit
      }
      // anything else, we use the default behavior:
      // Frame.handleEvent()
      return super.handleEvent(e);
    }
    

    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.*;
    
    public class BasicEventApplication {
      public static void main(String[] args) {
        YourMainWindow2 w = new YourMainWindow2();
        w.show();
      }
    }
    
    class YourMainWindow2 extends Frame {
      TextField a,b;
      Button but;
    
      public YourMainWindow2() {
        super("YourMainWindow Title");
        resize(400,200);
        setLayout(new FlowLayout());
        // for example, we add a few text fields
        // and a button
        add(new Label("Click the mouse..."));
        a = new TextField("0", 4);
        b = new TextField("0", 4);
        but = new Button("RESET");
        add(a);
        add(b);
        add(but);
      }
      // handle the WINDOW (and Scrollbar) events here
      public boolean handleEvent(Event e) {
        if ( e.id == Event.WINDOW_DESTROY ) {
          hide(); // hide the Frame
          // tell windowing system to free resources
          dispose();
          System.exit(0);  // exit
          return true;
        }
        // anything else, we use the default behavior:
        // Frame.handleEvent()
        return super.handleEvent(e);
      }
      // handle mouse events like you normally would
      public boolean mouseDown(Event e, int x, int y) {
        a.setText(String.valueOf(x));
        b.setText(String.valueOf(y));
        return true;
      }
      // handle buttons (and menus when you add them)
      // in action method
      public boolean action(Event e, Object arg) {
        if ( e.target == but ) {
          a.setText("0");
          b.setText("0");
          return true;
        }
        return false;
      }
    }
    

    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 method show() to activate the dialog box.

    import java.awt.*;
    
    public class DialogTest {
      public static void main(String[] args) {
        AMainWindow mw = new AMainWindow();
        mw.show();
      }
    }
    
    class AMainWindow extends Frame {
      Dialog d;
    
      public AMainWindow() {
        super("YourMainWindow Title");
        resize(200,200);
    
        add("Center", new Label
          ("Dialog test...hit a key"));
    
        // make dialog box with label inside and button
        // last parameter of true means 'modal'
        d = new Dialog(this, "Error Dialog", false);
        d.setLayout(new GridLayout(2,1));
        d.resize(200,200);
        d.add(new Label("something BAD happened!"));
        d.add(new Button("OK"));
      }
      // a key press triggers the dialog box
      public boolean keyDown(Event e, int key) {
        d.show();
        return true;
      }
    
      // handle the WINDOW (and Scrollbar) events here
      public boolean handleEvent(Event e) {
        if ( e.id == Event.WINDOW_DESTROY ) {
          hide(); // hide the Frame
          // tell windowing system to free resources
          dispose();
          System.exit(0);  // exit
          return true;
        }
        // anything else, we use the default behavior:
        // Frame.handleEvent()
        return super.handleEvent(e);
      }
    }
    

    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.

    Magercise

  • 3. Display a file name from FileDialog.
  • Applications: Menus

    A Java application can have a MenuBar object containing Menu objects that are comprised of MenuItem objects. Menu items can be strings, menus, checkboxes, and separators (a line across the menu).

    To add menus to any Frame or subclass of Frame:

    1. Create a MenuBar.
    2. Create a Menu.
    3. Create your MenuItems and add them to the Menu, in the order you want them to appear, from top to bottom.
    4. Add each Menu to the MenuBar in the order you want them to appear, from left to right.
    5. Add the MenuBar to the Frame by calling method Frame.setMenuBar().

    The following code shows a simple example of these steps:

    MenuBar mb = new MenuBar();  // Step 1
    Menu m = new Menu("File");   // Step 2
    m.add(new MenuItem("Open")); // Step 3
    m.add(new MenuItem("-"));    // add a separator
    m.add(new CheckboxMenuItem("Allow writing"));
    Menu sub = new Menu("Options..."); // Create a submenu
    sub.add(new MenuItem("Option 1"));
    m.add(sub);           // add sub to File menu
    mb.add(m);            // Step 4, add File menu to bar
    setMenuBar(mb);       // Step 5, set menu bar of your
                          // Frame subclass
    

    We suggest creating a separate subclass of Menu for each menu you wish to create, in order to isolate the menu selection events from other menus and the normal events (such as mouse clicks) for your Frame.

    When a menu item is selected, Menu.postEvent() is called, which by default tells the parent of the Menu (usually the surrounding Frame) to post the event. However, we want to handle events for menus directly in a Menu subclass rather than letting the event fall through to the event handler for the entire application.

    You must override the postEvent() method of each Menu subclass to capture menu selection events:

    // override postEvent.
    // e.arg is the selected menu item (a String)
    public boolean postEvent(Event e) {
      String item = (String) e.arg;
      if ( item.equals("selection 1") ) {
        ...
        return true;
      }
      else if ( item.equals("selection 2") ) {
        ...
        return true;
      }
      // if not handled, use normal behavior
      else return super.postEvent(e);
    }
    

    The following application builds a menu bar, shown below, that illustrates all menu construction facilities and incorporates our event handling strategy.

    import java.awt.*;
    
    public class MenuTest {
      public static void main(String[] args) {
        MainWindow w = new MainWindow();
        w.show();
      }
    }
    
    // Make a main window with two top-level menus:
    //     File and Help.
    // Help has a submenu and demonstrates
    //     a few interesting menu items.
    class MainWindow extends Frame {
      public MainWindow() {
        super("MenuTest Window");
        resize(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);
      }
    
      public void exit() {
          hide(); // hide the Frame
          // tell windowing system to free resources
          dispose();
          System.exit(0); // exit
      }
    }
    
    // Encapsulate the look and behavior of the File menu
    class FileMenu extends Menu {
      MainWindow mw;  // who owns us?
      public FileMenu(MainWindow m) {
        super("File");
        mw = m;
        add(new MenuItem("Open"));
        add(new MenuItem("Close"));
        add(new MenuItem("Exit"));
      }
      // respond to the Exit menu choice
      // This method does not pass unhandled events to the parent
      public boolean postEvent(Event e) {
        String item = (String) e.arg;
        if ( item.equals("Exit") ) mw.exit();
        else System.out.println
            ("Selected FileMenu " + item);
        return true;
      }
    }
    
    // Encapsulate the look and behavior of the Help menu
    class HelpMenu extends Menu {
      MainWindow mw;  // who owns us?
      public HelpMenu(MainWindow m) {
        super("Help");
        mw = m;
        add(new MenuItem("Fundamentals"));
        add(new MenuItem("Advanced"));
        add(new MenuItem("-"));
        add(new CheckboxMenuItem
          ("Have Read The Manual"));
        add(new CheckboxMenuItem
          ("Have Not Read The Manual"));
    
        // make a Misc sub menu of Help menu
        Menu subMenu = new Menu("Misc");
        subMenu.add(new MenuItem("Help!!!"));
        subMenu.add(new MenuItem("Why did that happen?"));
        add(subMenu);
      }
      // respond to a few menu items
      // This method does not pass unhandled events
      // to the parent
      public boolean postEvent(Event e) {
        String item = (String) e.arg;
        if ( item.equals("Fundamentals") )
          System.out.println("Fundamentals");
        else if ( item.equals("Help!!!") )
          System.out.println("Help!!!");
        // etc...
        return true;
      }
    }
    

    The following template can be used to begin most applications needing menus.

    import java.awt.*;
    import java.io.*;
    
    public class ApplicationTemplate {
      public static void main(String[] args) {
        YourMainWindow w = new YourMainWindow();
        w.show();
      }
    }
    
    class YourMainWindow extends Frame {
      Menu fileMenu;
      MenuBar mb;
    
      public YourMainWindow() {
        super("YourMainWindow Title");
        resize(200,200);
    
        // add what you want to this Frame
        add("Center", new Label
            ("An Application Template..."));
    
        fileMenu = new Menu("File");
        fileMenu.add(new MenuItem("Open"));
        fileMenu.add(new MenuItem("Close"));
        mb = new MenuBar();
        mb.add(fileMenu);
        setMenuBar(mb);
      }
    
      // handle the WINDOW (and Scrollbar) events here
      public boolean handleEvent(Event e) {
        if ( e.id == Event.WINDOW_DESTROY ) {
          // any window destroy event
          hide(); // hide the Frame
          // tell windowing system to free resources
          dispose();
          System.exit(0); // exit
          return true;
        }
        // anything else, we use the default behavior:
        // Frame.handleEvent()
        return super.handleEvent(e);
      }
    
      public boolean mouseDown(Event e, int x, int y) {
        return false;
      }
    
      // can handle menu events in one giant action()
      // [or subclass Menu]
      // handle button events here too..
      public boolean action(Event e, Object arg) {
        if ( e.target instanceof MenuItem ) {
          System.out.println
            ("Selected MenuItem " + arg);
          return true;
        }
        return false;
     }
    }
    

    The following template can be used for version 1.1 applications needing menus.

    import java.awt.*;
    import java.awt.event.*;
    
    public class ApplicationTemplate11 {
      public static void main(String[] args) {
        YourMainWindow11 w = new YourMainWindow11();
        w.show();
      }
    }
    
    class YourMainWindow11 extends Frame {
      Menu fileMenu;
      MenuBar mb;
    
      class MyMenuItem extends MenuItem
          implements ActionListener {
        MyMenuItem () {
          addActionListener (this);
        }
        MyMenuItem (String s) {
          super (s);
          addActionListener (this);
        }
        // can handle menu item events in one place
        public void actionPerformed (ActionEvent e) {
          System.out.println
            ("Selected MenuItem " + e.getActionCommand());
        }
      }
    
      public YourMainWindow11() {
        super("YourMainWindow Title");
        setSize(200,200);
    
        // add what you want to this Frame
        add(new Label("An Application Template..."),
            BorderLayout.CENTER);
    
        fileMenu = new Menu("File");
        fileMenu.add(new MyMenuItem("Open"));
        fileMenu.add(new MyMenuItem("Close"));
        mb = new MenuBar();
        mb.add(fileMenu);
        setMenuBar(mb);
        // handle the WINDOW closing event here
        addWindowListener (new WindowAdapter() {
                             public void windowClosing (WindowEvent e) {
                               // any window destroy event
                               setVisible(false); // hide the Frame
                               // tell windowing system to free resources
                               dispose();
                               System.exit(0); // exit
                             }
                           });
      }
    }
    

    Magercise

  • 4. Menus.
  • 5. A Four-Function Calculator (part two).
  • 6. Rubberbanding.
  • 7. Double-Buffering.
  • Menu Shortcuts

    One nice new feature of Java 1.1 is the ability to provide menu shortcuts or speed keys. For instance, in most applications that provide printing capabilities, pressing Ctrl-P initiates the printing process. In Java 1.0 applications, you could implement this in a roundabout way, but the menu wouldn't display the shortcut properly. Now, 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. Once there is a Java 1.1 version for the Macintosh, this would be the Command key. An optional boolean parameter to the constructor determines the need for the Shift key.

    Popup 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. Although Java 1.1 does not rectify that problem, you can associate a popup-menu with any Component, of which Applet is a subclass. A PopupMenu is similar to a Menu in that it holds MenuItems. However, instead of appearing at the top of a Frame, you pop it up over any component when the user generates the appropriate mouse event.

    The actual mouse interaction to generate the event is platform specific so Java includes the means to determine if a MouseEvent triggers the popup menu via the MouseEvent.isPopupTrigger method. It is then your responsibility to display the PopupMenu.

    The following code fragment demonstrates this:

    public class MyLabel extends Label {
      ...
      PopupMenu popup;
      public void init () {
        ...
        popup = new PopupMenu ("Some Title");
        popup.add (…) MenuItems
        add (popup);
        // Enable mouse event listening, w/o listening
        // If we add a mouse listener, we don't know what
        // to listen for and would have to duplicate code.
        addMouseListener (new MouseAdapter() {
                            public void mousePressed (MouseEvent e) {
                              if (e.isPopupTrigger())
                                popup.show(e.getComponent(),
                                           e.getX(), e.getY());
                            }
                          });
      }
    }
    

    Copyright © 1996-1997 MageLang Institute. All Rights Reserved.