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.
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.
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.
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.
% cp MyClass.java MyClass.java.orig
% cp MyClass.class MyClass.class.orig
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
% 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.
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.
-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:
java.awt.event
package:
import java.awt.event.*
action
method,
the table at the end of this document tells you to look for
Button
,
List
,
MenuItem
,
TextField
,
Checkbox
, and
Choice
objects.
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.
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.
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.
return
statements.
event.target
to be event.getSource()
.
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.
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:
% mkdir 1.0example
% mv DialogWindow.class 1.0example
% cp DialogWindow.java 1.0example
% 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
% 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
).
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
.
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);
}
...
}
% java DialogWindow
By using the DialogWindow application,
you can see that it handles all events properly.
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)
|
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)
|