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 1.1 version of AWT has some new features you might want to use.
- The new architecture enables faster, more robust implementations of the AWT, which means that your updated program might work better.
- Support for the old API will eventually be phased out.

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:

- The architecture has been improved to make large-scale GUI development more feasible and to add basic functionality that was missing.

  Architectural support has been added for event handling by non-components ("delegation"), data transfer (such as cut-copy-paste), desktop color schemes (to improve consistency of appearance), mouseless operation, and component-specific cursors. Not all of the features associated with these architecture improvements have been completely implemented. For example, although the data transfer architecture makes drag-and-drop possible, drag-and-drop isn't implemented in 1.1. JDK1.1 - AWT Enhancements has details on exactly what is implemented in the final 1.1 release.

- Method names, arguments, and functionality have been made consistent.

  These changes make it possible for programs such as GUI builders and JavaBeans-using programs to query components to determine the components' properties. They also make it easier for programmers to learn and use the AWT API.

- Miscellaneous quality improvements have been made and new features added.

  For example, image and graphics functionality has improved, and the `PopupMenu` and `ScrollPane` classes have been added. The `PopupMenu` class makes it possible to have a menu that is not attached to a menu bar. The `ScrollPane` class makes implementing scrolling areas easy, as well as increasing the speed of scrolling.

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:

- Converting to the new names. Much of this conversion can be done automatically.
- Converting to the new event scheme.

### 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:

- Change the source file so that it imports the `java.awt.event` package:

  >     import java.awt.event.*

- Figure out which components generate each event type. The table at the end of this document can help you know what to look for. For example, if you're converting event code that's in an `action` method, the table at the end of this document tells you to look for `Button`, `List`, `MenuItem`, `TextField`, `Checkbox`, and `Choice` objects.

- Change the class declaration so that the class implements the appropriate listener interfaces (as listed by the table at the end of this document). For example, if you're trying to handle an action event generated by a `Button`, the table tells you to implement the `ActionListener` interface.

  >     public class MyClass extends SomeComponent
  >                  implements ActionListener

  Alternative: Instead of implementing an interface, you can declare an inner class that extends an event adapter class. Inner classes are useful when you need to implement only one method of an interface, but the interface contains many other methods. See Using Inner Classes for Event Handling for more information.

- Determine where the components that generate the events are created. Just after the code that creates each one, register `this` as the appropriate type of listener. For example:

  >     newComponentObject.addActionListener(this);

  Alternative: If you use an inner class to handle the events, register an instance of that inner class instead. See Using Inner Classes for Event Handling for more information.

- Create empty implementations of all the methods in the listener interfaces your class must implement. Copy the event-handling code into the appropriate methods. For example, `ActionListener` has just one method, `actionPerformed`. So as a shortcut way of creating the new method and copying the event-handling code to it, you can simply change the signature of an `action` method from this:

  >     public boolean action(Event event, Object arg) {

  to this:

  >     public void actionPerformed(ActionEvent event) {

  Alternative: If you use an inner class to handle the events, you don't need to create empty implementations of methods. See Using Inner Classes for Event Handling for more information.

- Modify the event-handling code in these ways:
  - Delete all `return` statements.
  - Change references to `event.target` to be `event.getSource()`.
  - Delete any code that unnecessarily tests for which component the event came from. (Now that events are forwarded only if the generating component has a listener, you don't have to worry about receiving events from an unwanted component.)
  - Perform any other modifications required to make the program compile cleanly and execute correctly.

#### 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:

- `DialogWindow` handles window destroy events for itself.
- `DialogWindow` handles action events for the components it contains. Upon closer inspection, we can see that it contains only one component that can generate action events: a `Button`.
- `SimpleDialog` handles action events for the components it contains. Upon closer inspection, we can see that it contains three components that can generate action events: two `Button`s (Cancel and Set) and a `TextField`.
- Both `DialogWindow` and `SimpleDialog` contain non-event-handling code, so you can't eliminate them by moving their event-handling code elsewhere.

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.0 | 1.1
--- | ---
Event/Method | Generated By | Interface | Methods
`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