Migrating to 1.1 |
Why should you update a 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 [somewhere] 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:
The following two sections describe each step in detail, and then give an example.
- Replace deprecated methods with their 1.1 equivalents.
- Convert the program's event-handling code to use the new AWT event system.
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, calledupdateAWT
, uses on a UNIX utility calledsed
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 theupdateAWT
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, theComponent handleEvent
method (along with the methods it called, such asaction
) was the center of event handling. OnlyComponent
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 aComponent
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.
Making a
The process of making aComponent
a ListenerComponent
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:
- 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 forButton
,List
,MenuItem
,TextField
,Checkbox
, andChoice
objects.
- 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 theActionListener
interface, putting the event-handling code in theactionPerformed
method
- Change the class declaration so that the class imports the necessary types and implements the appropriate listener interfaces:
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.import java.awt.event.*; ... public class MyClass extends SomeComponent implements ActionListener {
- 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 anaction
method from this:to this:public boolean action(Event event, Object arg) {Alternative: If you use an adapter subclass to handle the events, you don't need to create empty implementations of methods.public void actionPerformed(ActionEvent event) {
- Modify the event-handling code in these ways:
- Delete all
return
statements.- Change references to
event.target
to beevent.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.
- 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:Alternative: If you use an inner class to handle the events, register an instance of that inner class instead.newComponentObject.addActionListener(this);
- 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 namedAppletButton
. The DialogWindow program is featured in the section How to Use Dialogs.You can find the 1.0 source code for DialogWindow (DialogWindow.java) in the online version of this tutorial.
Step 1: Replace Deprecated Methods with Their 1.1 Equivalents
- 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- 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- 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 %As you can see, the example compiles successfully. However, a few calls or overrides of deprecated methods remain. The% 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 %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.
By using the DialogWindow program, both as an applet and as an application, we can see that it handles all events properly.
- 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: aButton
.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: twoButton
s (Cancel and Set) and aTextField
.- Both
DialogWindow
andSimpleDialog
contain non-event-handling code, so you can't eliminate them by moving their event-handling code elsewhere.
- 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 ofWindowListener
, and that action events generated by buttons and text fields are handled by theactionPerformed
method ofActionListener
.
- 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.
Instead of implementing theimport 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); } }WindowListener
interface,DialogWindow
could simply contain an inner class that extendsWindowAdapter.
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. (To see the whole program, go toDialogWindow.java
.)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!... ... }
Migrating to 1.1 |