The JavaTM Tutorial

| Start of Tutorial > Start of Trail > Start of Lesson | Search

Trail: JDK(TM) 1.1 -- And Beyond!
Lesson: Migrating to 1.1

## How to Convert Code that Uses the AWT

> Why should you update a 1.0 program to the 1.1 AWT API? Here are five possible reasons:
> - The 1.1 version of AWT has some new features you want to use. See AWT Enhancements for a summary of new features.
> - The new AWT architecture enables faster, more robust implementations of the AWT, which means that the updated program might work better.
> - You plan to use the Swing components, which rely on the new event architecture. See Using Swing Components for information on the Swing components.
> - The program is one of the rare ones that is affected by incompatible AWT changes. You can find a list of possibly incompatible bug fixes in the document Incompatible Changes in the 1.1 AWT API.
> - You want the 1.1 Java compiler to compile the program without deprecation warnings.

> Converting a 1.0 program to the 1.1 AWT API usually requires two steps:

> 1. Replace deprecated methods with their 1.1 equivalents.
> 2. Convert the program's event-handling code to use the new AWT event system.
> The following two sections describe each step in detail, and then give an example.

### Step 1: Replace Deprecated Methods with Their 1.1 Equivalents

> Because so many methods were deprecated JavaSoft provides a script to help you convert 1.0 programs to the 1.1 versions. This script, called `updateAWT`, uses on a UNIX utility called `sed` to change the names of many deprecated 1.0 AWT methods into their 1.1 equivalents. 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. For instructions, see Platform-specific Details: Using the `updateAWT` Script.

> You'll probably have to make some changes by hand, whether or not you use the `updateAWT` script. As described in How to Convert Your Program, you can get a list of the deprecated methods in the program by compiling its files with the `-deprecation` flag.

> Once you know which deprecated methods the program uses, look up each method in the section Alternatives to Deprecated Methods in the AWT. Then replace each deprecated method with its 1.1 alternative. Most of the changes you need to make are straightforward, except those to event-handling code, which are described in the next section.

### Step 2: Convert Event-Handling Code

> In 1.0, 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. That's the scheme that this section illustrates.

> 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.

> 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.

> For more information about 1.1 event handling, see Event Handling.

> ### Making a `Component` a Listener

> The process of making a `Component` a listener can be straightforward, once you figure out which events a program handles and which components generate the events. If you're using a Java compiler from JDK 1.1.1 or later, then 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:

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

> 2. By looking up each event type in the Event-Conversion Table, note which listener interfaces the listener should implement, and which methods within each interface should contain event-handling code. For example, if you're trying to handle an action event generated by a `Button`, the table tells you to implement the `ActionListener` interface, putting the event-handling code in the `actionPerformed` method

> 3. Change the class declaration so that the class imports the necessary types and implements the appropriate listener interfaces:

>    >     import java.awt.event.*;
>    >     ...
>    >     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 Adapters and Inner Classes to Handle AWT Events for more information.

> 4. 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 adapter subclass to handle the events, you don't need to create empty implementations of methods. See Using Adapters and Inner Classes to Handle AWT Events for more information.

> 5. 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.

> 6. 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 Adapters and Inner Classes to Handle AWT Events for more information.

> 7. Compile and test your program. If your program is ignoring some events, make sure you added the correct event-listener object as a listener to the correct event-generating object.

### 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`. The DialogWindow program is featured in the section How to Use Dialogs.

### Step 1: Replace Deprecated Methods with Their 1.1 Equivalents

1. 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

2. 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

3. 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 example compiles successfully. However, a few calls or overrides of deprecated methods remain. The `Event` arguments to these methods are a tell-tale sign that the methods contain event-handling code.

   ### Step 2: Convert Event-Handling Code

   To convert DialogWindow, follow the sequence described previously in Making a Component a Listener.

   1. The first and hardest task is determining which components generate events that must be handled. Compiling with the `-deprecation` flag tells us that DialogWindow has three 1.0-style event-handling methods:
      - `DialogWindow.handleEvent`
      - `DialogWindow.action`
      - `SimpleDialog.action`

      Studying DialogWindow's code tells us these things about its event handling architecture:

      - `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.

   2. Now that we know which objects generate which events, it's easy to determine which interfaces the event handlers should implement. Consulting the Event-Conversion Table tells us that WINDOW_DESTROY corresponds to the `windowClosing` method of `WindowListener`, and that action events generated by buttons and text fields are handled by the `actionPerformed` method of `ActionListener`.

   3. Now all that's left is to implement the event-handling methods and register the event listener. The following example gives the highlights of the event-related code 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.` This change makes the empty method bodies unnecessary.

      The following are the highlights of a `DialogWindow` class that uses an inner class to handle window events. Significant changes from the 1.1 window listener version are in bold.

      >     public class DialogWindow extends Frame
      >     			  implements ActionListener {
      >         ...
      >         public DialogWindow() {
      >     	...
      >             Button button = new Button("Click to bring up dialog");
      >     	button.addActionListener(this);
      >     	...
      >     	addWindowListener(new WindowAdapter() {
      >                 public void windowClosing(WindowEvent event) {
      >                     if (inAnApplet) {
      >                         dispose();
      >                     } else {
      >                         System.exit(0);
      >                     }
      >     	    }
      >     	});
      >         }

      >         ...//No empty windowXXX method implementations!...

      >         ...
      >     }

   By using the DialogWindow program, both as an applet and as an application, we can see that it handles all events properly.

   | Start of Tutorial > Start of Trail > Start of Lesson | Search