Action events are generated for the following objects:
Table 6: Objects generating Action Events
GUI Object Action
Button Click on Button
List Double-click on an item MenuItem Click on MenuItem TextField Press <Enter> key
An ActionListener can be registered with each of these objects, and its method actionPerformed() is called when the user performs the indicated activity.
An ActionEvent has two methods that the programmer may find to be of use:
public String getActionCommand() public int getModifiers()
Each ActionEvent carries around an ``action command''. This command may be set by the Button or MenuItem by their setActionCommand(String) method. There is no such method for List or TextField. The value of the action command (unless reset) is
Table 7: Value of Action Command GUI Object action command
Button label
List ???
MenuItem label TextField ???
The action command gives runtime information about the context in which the event occurred. This is semantic-level information, rather than low-level information: the text showing in the Button is usually enough useful information. If low-level information is required, the source object can be obtained from the methodgetSource() (or equivalent methods). This method is inherited by every event from the superior class java.util.EventObject.
We shall illustrate use of action events by four programs which do basically the same thing, but use different GUI elements to do this. The common part of these will be a Label which can have its
foreground color set to different values. The color can be selected in different ways for each program, but they will all invoke the sameActionListener. This ActionListener is defined by the following:
import java.awt.Component;
import java.awt.Color;
import java.awt.event.ActionListener;
/**
* An ActionListener that changes the foreground * color of a component passed in by the constructor *
* @author Jan Newmarch */
public class SetColor implements ActionListener {
final Color colors[] = {Color.red, Color.blue, Color.green};
final String colorLabels[] = {"red", "blue", "green"};
private Component comp;
public SetColor(Component c) { comp = c;
} /**
* Invoked by an action event somewhere * resets the foreground of a component passed * in to the constructor
*/
public void actionPerformed(ActionEvent e) { String colorName = e.getActionCommand();
// search for Color matching color name for (n = 0; n < colorLabels.length; n++) { if (colorLabels[n].equals(colorName)) {
// found a match, set foreground comp.setForeground(colors[n]);
return;
} }
System.out.println("Unknown color: " + colorName);
} }
The first program to use this has a row of three buttons along the top and a label to below them. A single SetColor listener will be created and registered with each button. The application looks like
The code is
import java.awt.*;
import SetColor;
public class ButtonColor extends Frame { public static void main(String argv[]) {
new ButtonColor().show();
}
public ButtonColor() {
// the label that will be colored
Label label = new Label("Click on button to change color");
// a panel to hold the buttons Panel panel = new Panel();
// buttons for each color
Button red = new Button("red");
Button blue = new Button("blue");
Button green = new Button("green");
// set geometry
panel.setLayout(new FlowLayout());
panel.add(red);
panel.add(blue);
panel.add(green);
add(panel, "North");
add(label, "Center");
pack();
// add the listener
SetColor sc = new SetColor(label);
red.addActionListener(sc);
blue.addActionListener(sc);
green.addActionListener(sc);
} }
The second program to use the SetColor listener will just change elements of the user interface. That is, instead of a set of buttons, it will use a list to the left of the label. In this version we shall only implement the double-click action, leaving single-click till later (that uses a different type of event). The application looks like
The code is import java.awt.*;
import SetColor;
public class ListColor extends Frame { public static void main(String argv[]) {
new ListColor().show();
}
public ListColor() {
// the label that will be colored
Label label = new Label("Double-click to change color");
// the list of colors List colors = new List(3);
colors.add("red");
colors.add("blue");
colors.add("green");
// set geometry add(colors, "West");
add(label, "Center");
pack();
// add the listener
SetColor sc = new SetColor(label);
colors.addActionListener(sc);
} }
Note that we have not changed the application code at all, only the GUI code. In this we are partly lucky since we are handling the same event type in both programs, but even handling different types does not cause many changes.
The third program will make the same kind of change. This time we shall use a menu of colors to make the selection. Each item in the menu will have the same listener added, just as for the buttons in the first program. The application looks like
The code is import java.awt.*;
import SetColor;
public class MenuColor extends Frame { public static void main(String argv[]) {
new MenuColor().show();
}
public MenuColor() {
// the label that will be colored
Label label = new Label("Select color from menu");
// the menu bar
MenuBar mb = new MenuBar();
Menu color = new Menu("Color");
mb.add(color);
// menu color items
MenuItem red = new MenuItem("red");
MenuItem blue = new MenuItem("blue");
MenuItem green = new MenuItem("green");
color.add(red);
color.add(blue);
color.add(green);
// set the geometry setMenuBar(mb);
add(label, "Center");
pack();
// add the listener
SetColor sc = new SetColor(label);
red.addActionListener(sc);
blue.addActionListener(sc);
green.addActionListener(sc);
} }
Again there is no change to the application code.
The last example gives the last variation on this theme, using a TextField for color selection. The application looks like
The code is import java.awt.*;
import SetColor;
public class TextFieldColor extends Frame { public static void main(String argv[]) {
new TextFieldColor().show();
}
public TextFieldColor() {
// the label that will be colored
Label label = new Label("Enter color in the TextField");
// the text field to enter the color TextField text = new TextField(20);
// set geometry add(text, "North");
add(label, "Center");
pack();
// add the listener
SetColor sc = new SetColor(label);
text.addActionListener(sc);
} }
This last piece of code is rather lacking in ease of use, as it gives no clues as to what are allowable text values!
Adjustment Events
Adjustment events are only generated for objects of class Scrollbar in Java 1.1. There is not so much need to use this class in Java 1.1, as there is also aScrollPane class which looks after most details of handling a viewport onto a component.
A listener of class AdjustmentListener is added to a Scrollbar by the method public void addAdjustmentListener(AdjustmentListener)
The user can interact with the scrollbar by clicking the mouse within it, by dragging the slider or by keyboard interaction such as the arrow keys or PageUp/PageDown keys. These all cause the method public void adjustmentValueChanged(AdjustmentEvent)
to be called in the listener.
There is only the one method called despite the variety of ways that the user can interact with the scrollbar. If the application needs to distinguish between these, it can call the
method getAdjustmentType() on the AdjustmentEvent. This will return one of the four values
• UNIT_INCREMENT - down one ``line''
• UNIT_DECREMENT - up one ``line''
• BLOCK_INCREMENT - down one ``page''
• BLOCK_DECREMENT - up one ``page''
The actual value of the scrollbar can be found from the method getValue() of the AdjustmentEvent. To use this value, you need to know where on the scale from minimum to maximum it occurs. These - and much other information - are available from the event of class Adjustable in which the event occurred (right now we know this is a Scrollbar but it could be other things in the future - for example,
a Scale object).
Component Events
Most applications will not need to use events of type ComponentEvent. This is used for tracking movement, resizing and visibility. An application will generally function perfectly well by ignoring these events: the AWT toolkit will look after things such as calling layout managers on resize.
There are occasions when an application may want to track such events. For example, a visually intensive piece of graphics such as animation should cease when the display object becomes invisible, so it will want to track visibility changes. A ``smart'' text display may want to change the size of the font used according to the amount of space it has, so it will want to track size changes.
An application wanting to track such changes registers a listener that implements ComponentListener.
This interface defines four methods that the listener must implement:
public void componentHidden(ComponentEvent);
public void componentMoved(ComponentEvent);
public void componentResized(ComponentEvent);
public void componentShown(ComponentEvent);
In objects of class ComponentEvent the id is used field to distinguish between four
types: COMPONENT_HIDDEN, COMPONENT_MOVED, COMPONENT_RESIZED andCOMPONENT_
SHOWN. The AWT uses this value to select which of the four listener methods to call, so you are unlikely to need to look at this field.
The ComponentEvent class supplies a method public Component getComponent()
if you need to determine which component has called the listener.
Here is a program to track resize and movement events on the toplevel Frame:
import java.awt.*;
import java.awt.event.ComponentEvent;
public class TrackResize extends Frame { public static void main(String argv[]) {
new TrackResize().show();
}
public TrackResize() {
Label label = new Label();
add(label);
pack();
addComponentListener(new Tracker(label));
} }
class Tracker implements ComponentListener { private Label label;
Tracker(Label l) { label = l;
}
public void componentHidden(ComponentEvent e) { // empty
}
public void componentMoved(ComponentEvent e) { showGeometry(e);
}
public void componentResized(ComponentEvent e) { showGeometry(e);
}
public void componentShown(ComponentEvent e) { // empty
}
private void showGeometry(ComponentEvent e) { Component c = e.getComponent();
Dimension d = c.getSize();
Point p = c.getLocation();
label.setText("Position: (" + p.x + "," + p.y + ") Size: (" + d.width + "," + d.height + ")");
} }
The Tracker class inherits only from Object. Because it has to implement all of the ComponentListener interface it ends up with empty implementations of
thecomponentHidden() and componentShown() methods. This may become mildly annoying if it had to be done frequently, so there is a ``convenience'' classComponentAdaptor which defines all these methods as empty ones. Using this, you can inherit from ComponentAdaptor and then just override the
methods you need. The single inheritance model of Java does of course then require that the listener cannot also inherit from other classes, so this may be of limited value.