Back to AWT Enhancements TOC

How to Convert Programs to the 1.1 AWT API

The architecture of the AWT has improved greatly in 1.1. This improvement required making some changes that affect compatibility. Specifically, programs that use 1.1 features do not run within runtime systems that are based on earlier releases. However, runtime systems based on 1.1 do run programs compiled under 1.0, 1.0.1, and 1.0.2, as long as the programs don't depend on bugs in the earlier releases. (You can find a list of these possibly incompatible bug fixes in the document Incompatible Changes in the 1.1 AWT API.) Programs that use only 1.0.X features but are compiled under 1.1 appear to run in 1.0.X runtime systems, but this compatibility hasn't been rigorously tested and is not guaranteed.

For example, any 1.0 applet should successfully compile under 1.1. And whether you use the old (1.0) class files or recompile and use new (1.1) class files, the 1.0 applet will work in 1.1-based browsers. Also, we believe that the new (1.1) class files will work in old (1.0-based) browsers, as long as you make no changes to the applet's source. But if you change the applet to use any 1.1 feature, the applet won't run in browsers such as Netscape 3.0 that haven't been updated to the 1.1 API.

So why should you update your programs to the 1.1 AWT API? Three reasons:

The rest of this document explains how the AWT has changed and how to convert your program. It then provides an example of converting a program to 1.1.

How the AWT Has Changed

The AWT has changed in three ways:

You can find more information on event-handling changes later in this document. See JDK1.1 - AWT Enhancements for more complete information about how the AWT has changed.

How to Convert Your Program

Converting a program to the 1.1 AWT has two major phases:

General Instructions

  1. First, save a copy of the original program -- both the Java source code and the Java bytecodes. You'll need the copy until all the Java runtime systems the program might execute in have been converted to 1.1. For example, licensees such as Netscape and Microsoft might take a few months after the final JDK 1.1 release to update their own products to include 1.1. For this reason, you might want to delay releasing a 1.1-based applet to the web (or provide both 1.0 and 1.1 versions) until you think that the applet's intended users have upgraded to the new release. Here's an example of saving a copy of a program on a UNIX system:
    % cp MyClass.java MyClass.java.orig
    % cp MyClass.class MyClass.class.orig
    
  2. Convert your source code -- automatically if possible -- so that it uses the new names for methods whose names have changed.

    We provide a sed script that performs much of the conversion automatically. (For details on what the script converts, see Simple Name Changes.) The script is designed for the UNIX sed command. If you're developing on a PC, you might be able to run the script using a product such as MKS Toolkit, which provides PC versions of UNIX tools. Here's how to use the sed script at a shell prompt on a UNIX system:

    % updateAWT MyClass.java > tmp.java
    

    Check the changes to make sure nothing obviously bad happened. For example, on a UNIX system, you might execute the following command:

    % diff MyClass.java tmp.java
    
    And then after confirming that the changes look OK:
    % mv tmp.java MyClass.java
    

  3. Try to compile the program under 1.1. Make sure you're using a 1.1 compiler. Here's an example of compiling on a UNIX system:
    % javac MyClass.java
    

    You might see compilation errors or warnings. The most common ones warn you that your program uses a deprecated method or uses a method that couldn't be found.

    If your program calls any deprecated methods -- pre-1.1 methods whose use we discourage for some reason -- the compiler displays a warning. For example:

    % javac MyClass.java
    Note: MyClass.java uses a deprecated API.  Recompile with "-deprecation"
    for details.
    1 warning
    %
    

    Note: The 1.1.1 Java compiler warns you when a program overrides a deprecated method, but the 1.1 compiler does not. The 1.1 compiler warns you only when a program calls a deprecated method. For example, the 1.1 compiler won't usually warn you if a program overrides the action method, since most implementations of action don't call the superclass's implementation.

    To get information about each source file's use of deprecated methods, use the -deprecation option of the Java compiler. For example:

    % javac -deprecation MyClass.java
    MyClass.java:18: Note: The method boolean handleEvent(java.awt.Event) in
    class java.awt.Component has been deprecated, and class MyClass overrides
    it.
        public boolean handleEvent(Event event) {
                       ^
    MyClass.java:26: Note: The method boolean handleEvent(java.awt.Event) in
    class java.awt.Component has been deprecated.
            return super.handleEvent(event);
                                    ^
    Note: MyClass.java uses a deprecated API.  Please consult the
    documentation for a better alternative.
    2 warnings
    

    You can consult Deprecated Methods in the 1.1 AWT for information about alternatives to each deprecated method. (It refers you back to this document for information on event-related methods.)

    If you get a compilation error saying that a method couldn't be found, then the sed script might have incorrectly changed the name of a method. See Simple Name Changes for help in correcting the problem.

  4. Make remaining changes by hand until the program compiles without warnings. Most of the changes that you're likely to make by hand involve converting to the 1.1 event model. This document gives you an overview of the 1.1 event model and tells you how to convert event-handling code.

  5. Test your program by executing it.

How to Convert Event-Handling Code

First, let's review how event handling happened before 1.1. Before 1.1, the Component handleEvent method (along with the methods it called, such as action) was the center of event handling. Only Component objects could handle events, and the component that handled an event had to be either the component in which the event occurred or a component above it in the component containment hierarchy.

In 1.1, event handling is no longer restricted to objects in the component containment hierarchy, and the handleEvent method is no longer the center of event handling, Instead, objects of any type can register as event listeners. Event listeners receive notification only about the types of events they've registered their interest in. Never again will you have to create a Component subclass just to handle events.

When upgrading to the 1.1 release, the simplest way to convert event-handling code is to leave it in the same class, making that class a listener for that type of event.

Another possibility is to centralize event-handling code in one or more non-Component listeners. This approach lets you separate the GUI of your program from implementation details, It requires that you modify your existing code so that the listeners can get whatever state information they require from the components. This approach can be worth your while if you're trying to keep your program's architecture clean.

A third possibility, which we don't recommend unless you're already extending a Component, is to override one of the processXxx methods. This and the other event-handling approaches are discussed in the design document Delegation Event Model.

We recommend that you do not mix the 1.0 event model with the 1.1 event model in the same program. The results would be unpredictable and might be difficult to debug.

Making a Component a Listener

The biggest part of converting most 1.0 AWT-using programs to the 1.1 API is converting the event-handling code. The process can be straightforward, once you figure out which events a program handles and which components generate the events. If you're using the 1.1.1 Java compiler, compiling with the -deprecation flag generates a list that includes all old-style event handling methods. (Before 1.1.1, the compiler didn't generate a complete list, so you had to search for "Event" in a source file.) While you're looking at the code, you should note whether any classes exist solely for the purpose of handling events; you might be able to eliminate such classes.

Here are the steps to follow when converting a 1.0 component into a listener:

Using Inner Classes for Event Handling

Inner classes are useful when you need to implement an interface that contains many methods, but you want to implement only one or two of the methods. This section tells you how to write an event handler using an inner class, without getting into details about inner classes in general. For general information about inner classes, see Inner Classes.

Implementing an event-handling inner class is a variation on making a class implement an event-listener interface. As before, you determine which interface corresponds to the events your class needs to handle. But instead of implementing the interface, you create an inner class that extends the adapter corresponding to the interface. For example, instead of implementing WindowListener, you can implement an inner class that extends WindowAdapter. Then you simply create an instance of your inner class and register it as the appropriate kind of listener -- for example, with the addWindowListener method. Here is an example:

public class MyClass ... {
    ...
    //Where the window is created:
        newWindow.addWindowListener(new MyInnerClass());
    ...
    class MyInnerClass extends WindowAdapter {
        public void windowClosing(WindowEvent event) {
            if (inAnApplet) {
                dispose();
            } else {
                System.exit(0);
            }
        }
    }
    ...
}

After compilation, the inner class bytecodes are put in a separate .class file named something like this: MyClass$MyInnerClass.class. For a complete example that uses an inner class, see innerclass/DialogWindow.java.

Example: Converting DialogWindow

This section shows how to convert a program called DialogWindow from the 1.0 API to the 1.1 API. DialogWindow is an application, but it can also run as an applet, with the help of a class named AppletButton. (Readers of The Java Tutorial might find this program familiar, since it's featured in the section "How to Use Dialogs".)

Below is the 1.0 version of DialogWindow (here's a link to the source code), running as an applet with the help of AppletButton:


Since you can't run the applet, here's a snapshot of the window (Frame) the button brings up:

And here's a snapshot of the dialog for the window:


Step 1: Make Copies

Move the 1.0 source and bytecode files to a safe place, keeping a copy of the source file that you can modify. For example, on a UNIX system:
% mkdir 1.0example
% mv DialogWindow.class 1.0example
% cp DialogWindow.java 1.0example

Step 2: Convert Automatically

Perform as much automatic conversion as possible. For example:
% updateAWT DialogWindow.java > tmp.java
% diff DialogWindow.java tmp.java
33c33
<         dialog.show();
---
>         dialog.setVisible(true);
38c38
<         textArea.appendText(text + "\n");
---
>         textArea.append(text + "\n");
47c47
<         window.show();
---
>         window.setVisible(true);
87c87
<         hide();
---
>         setVisible(false);
% mv tmp.java DialogWindow.java

Step 3: Compile

Compile DialogWindow, making sure to use the 1.1 compiler. For example:
% which javac
/usr/local/java/jdk1.1.1/solaris/bin/javac
% javac DialogWindow.java
Note: DialogWindow.java uses a deprecated API.  Recompile with
"-deprecation" for details.
1 warning
%
% javac -deprecation DialogWindow.java
DialogWindow.java:18: Note: The method boolean handleEvent(java.awt.Event) in
class java.awt.Component has been deprecated, and class DialogWindow overrides
it.
    public boolean handleEvent(Event event) {
                   ^
DialogWindow.java:26: Note: The method boolean handleEvent(java.awt.Event) in
class java.awt.Component has been deprecated.
        return super.handleEvent(event);
                                ^
DialogWindow.java:29: Note: The method boolean action(java.awt.Event,
java.lang.Object) in class java.awt.Component has been deprecated, and class
DialogWindow overrides it.
    public boolean action(Event event, Object arg) {
                   ^
DialogWindow.java:81: Note: The method boolean action(java.awt.Event,
java.lang.Object) in class java.awt.Component has been deprecated, and class
SimpleDialog overrides it.
    public boolean action(Event event, Object arg) {
                   ^
Note: DialogWindow.java uses a deprecated API.  Please consult the
documentation for a better alternative.
5 warnings
%
As you can see, the class compiles successfully, but it calls or overrides methods that have been deprecated (handleEvent and action).

Step 4: Make Changes by Hand

For the DialogWindow program, this step consists solely of converting the event-handling code, as described previously in Making a Component a Listener. Searching for "Event" in DialogWindow.java lets you find the event-handling code in the two classes (DialogWindow and SimpleDialog) that comprise the program.

Here's an overview of event handling in the DialogWindow program:

The current locations of the event-handling code make sense. Another way that might make sense is to have DialogWindow handle all events, since it is the controlling class in this application. Yet another possibility is to introduce a non-Component controlling class that handles all action events. To convert the DialogWindow program, we'll keep its event-handling code in the same components as before but make the components implement listener interfaces.

The following example gives the highlights of the event-related code in the converted DialogWindow program. Significant changes are in bold.

import java.awt.event.*;

public class DialogWindow extends Frame 
			  implements WindowListener,
				     ActionListener {
    ...
    public DialogWindow() {
	...
        Button button = new Button("Click to bring up dialog");
	button.addActionListener(this);
	...
	addWindowListener(this);
    }

    public void windowClosed(WindowEvent event) {
    }

    public void windowDeiconified(WindowEvent event) {
    }

    public void windowIconified(WindowEvent event) {
    }

    public void windowActivated(WindowEvent event) {
    }

    public void windowDeactivated(WindowEvent event) {
    }

    public void windowOpened(WindowEvent event) {
    }

    public void windowClosing(WindowEvent event) {
        if (inAnApplet) {
            dispose();
        } else {
            System.exit(0);
        }
    }

    public void actionPerformed(ActionEvent event) {
        if (dialog == null) {
            dialog = new SimpleDialog(this, "A Simple Dialog");
        }
        dialog.setVisible();
    }
    ...
}

class SimpleDialog extends Dialog implements ActionListener {
    ...
    SimpleDialog(Frame dw, String title) {
	...
        field = new TextField(40);
	field.addActionListener(this);
	...
        Button b = new Button("Cancel");
	b.addActionListener(this);
        setButton = new Button("Set");
	setButton.addActionListener(this);
	...
    }

    public void actionPerformed(ActionEvent event) {
	Object source = event.getSource();
        if ( (source == setButton)
           | (source == field)) {
            parent.setText(field.getText());
        }
        field.selectAll();
        setVisible(false);
    }
}
Instead of implementing the WindowListener interface, DialogWindow could simply contain an inner class that extends WindowAdapter. Here are the highlights of DialogWindow implemented with an inner class. Significant changes from the 1.0 version are in bold.
import java.awt.event.*;

public class DialogWindow extends Frame 
			  implements ActionListener {
    ...
    public DialogWindow() {
	...
        Button button = new Button("Click to bring up dialog");
	button.addActionListener(this);
	...
	addWindowListener(new DWAdapter());
    }

    class DWAdapter extends WindowAdapter {
        public void windowClosing(WindowEvent event) {
            if (inAnApplet) {
                dispose();
            } else {
                System.exit(0);
            }
        }
    }

    public void actionPerformed(ActionEvent event) {
        if (dialog == null) {
            dialog = new SimpleDialog(this, "A Simple Dialog");
        }
        dialog.setVisible(true);
    }
    ...
}

Step 5: Test

Since the DialogWindow program is an application, we test it by executing it in the Java interpreter. For example:
% java DialogWindow
By using the DialogWindow application, you can see that it handles all events properly.


Event Conversion Table

The following table maps 1.0 events to their 1.1 counterparts. The first column lists each 1.0 event type, along with the name of the method (if any) that's specific to the event. Where no method is listed, the event is always handled in the handleEvent method. The second column lists the 1.0 components that can generate the event type. The third column lists the listener interface that helps you handle the 1.1 equivalents of the listed events. The fourth column lists the methods in each listener interface.

1.01.1
Event/MethodGenerated ByInterfaceMethods
ACTION_EVENT/action Button, List, MenuItem, TextField ActionListener actionPerformed(ActionEvent)
Checkbox, CheckboxMenuItem, Choice ItemListener itemStateChanged(ItemEvent)
WINDOW_DESTROY
WINDOW_EXPOSE
WINDOW_ICONIFY
WINDOW_DEICONIFY
Dialog, Frame WindowListener windowClosing(WindowEvent)
windowOpened(WindowEvent)
windowIconified(WindowEvent)
windowDeiconified(WindowEvent)
windowClosed(WindowEvent) (no 1.0 equivalent)
windowActivated(WindowEvent) (no 1.0 equivalent)
windowDeactivated(WindowEvent) (no 1.0 equivalent)
WINDOW_MOVED Dialog, Frame ComponentListener componentMoved(ComponentEvent)
componentHidden(ComponentEvent) (no 1.0 equivalent)
componentResized(ComponentEvent) (no 1.0 equivalent)
componentShown(ComponentEvent) (no 1.0 equivalent)
SCROLL_LINE_UP
SCROLL_LINE_DOWN
SCROLL_PAGE_UP
SCROLL_PAGE_DOWN
SCROLL_ABSOLUTE
SCROLL_BEGIN
SCROLL_END
Scrollbar AdjustmentListener
(or use the new ScrollPane class)
adjustmentValueChanged(AdjustmentEvent)
LIST_SELECT
LIST_DESELECT
Checkbox, CheckboxMenuItem, Choice, List ItemListener itemStateChanged(ItemEvent)
MOUSE_DRAG/mouseDrag
MOUSE_MOVE/mouseMove
Canvas, Dialog, Frame, Panel, Window MouseMotionListener mouseDragged(MouseEvent)
mouseMoved(MouseEvent)
MOUSE_DOWN/mouseDown
MOUSE_UP/mouseUp
MOUSE_ENTER/mouseEnter
MOUSE_EXIT/mouseExit
Canvas, Dialog, Frame, Panel, Window MouseListener mousePressed(MouseEvent)
mouseReleased(MouseEvent)
mouseEntered(MouseEvent)
mouseExited(MouseEvent)
mouseClicked(MouseEvent) (no 1.0 equivalent)
KEY_PRESS/keyDown
KEY_RELEASE/keyUp
KEY_ACTION/keyDown
KEY_ACTION_RELEASE/keyUp
Component KeyListener keyPressed(KeyEvent)
keyReleased(KeyEvent)
keyTyped(KeyEvent) (no 1.0 equivalent)
GOT_FOCUS/gotFocus
LOST_FOCUS/lostFocus
Component FocusListener focusGained(FocusEvent)
focusLost(FocusEvent)
No 1.0 equivalent. ContainerListener componentAdded(ContainerEvent)
componentRemoved(ContainerEvent)
No 1.0 equivalent. TextListener textValueChanged(TextEvent)


Back to AWT Enhancements TOC
By Kathy Walrath