First, what is an event?
Classes related events in AWT:
We have already seen, for example, that a Button
can generate an ActionEvent that must be handled
by an ActionListener instance.
Let us review this example once more:
What really happens when the button is pressed?
An overview of some important events in AWT:
Next, a tour of some "listeners":
Note:
(For example, when a user presses a button, you the
programmer may need to perform some computation).
Button b = new Button ("Quit");
public interface ActionListener extends EventListener {
public abstract void actionPerformed (ActionEvent a);
}
b.addActionListener (this); // "this" refers to the frame.
b.addActionListener (
new ActionListener () {
public void actionPerformed (ActionEvent a)
{
// ... do whatever needs to be done ...
}
}
);
Other, less frequently used events include:
ComponentEvent and ContainerEvent.
Other, less frequently used listeners include:
ComponentListener and ContainerListener.
public interface ActionListener extends EventListener {
public abstract void actionPerformed (ActionEvent a);
}
public interface MouseListener extends EventListener {
public abstract void mouseClicked (MouseEvent m);
public abstract void mouseEntered (MouseEvent m);
public abstract void mouseExited (MouseEvent m);
public abstract void mousePressed (MouseEvent m);
public abstract void mouseReleased (MouseEvent m);
}
public interface MouseMotionListener extends EventListener {
public abstract void mouseDragged (MouseEvent m);
public abstract void mouseMoved (MouseEvent m);
}
public interface KeyListener extends EventListener {
public abstract void keyPressed (KeyEvent k);
public abstract void keyReleased (KeyEvent k);
public abstract void keyTyped(KeyEvent k);
}
public interface ItemListener extends EventListener {
public abstract void itemStateChanged (ItemEvent i);
}
public interface FocusListener extends EventListener {
public abstract void focusGained (FocusEvent f);
public abstract void focusLost (FocusEvent f);
}
public interface AdjustmentListener extends EventListener {
public abstract void adjustmentValueChanged (AdjustmentEvent a);
}
public interface WindowListener extends EventListener {
public abstract void windowOpened (WindowEvent w);
public abstract void windowClosed (WindowEvent w);
public abstract void windowClosing(WindowEvent w);
public abstract void windowIconified (WindowEvent w);
public abstract void windowDeiconified (WindowEvent w);
public abstract void windowActivated (WindowEvent w);
public abstract void windowDeactivated (WindowEvent w);
}
public interface TextListener extends EventListener {
public abstract void textValueChanged (TextEvent t);
}
Java 1.1 introduced new syntax to allow programmers to define
classes inside top-level classes. One motivation was to improve
event-handling.
There are four types of nested classes:
(Only one local class needs to be defined).
We will use an example with two canvases to illustrate:
Here is what we want the frame to look like (after a few
mouse-clicks in each canvas):
Here is the code:
(source file)
Note:
The above approach of having the frame implement the
listeners is undesirable for many reasons:
To solve this problem, Java provides the use of so-called
local classes:
Note:
Implementing the MouseListener interface in a
local class is done similarly:
(source file)
Note:
We will improve the above code in the following ways:
Here is the code:
(source file)
import java.awt.*;
import java.awt.event.*; // Needed for ActionListener.
class NewFrame extends Frame
implements ActionListener, MouseListener {
// Data.
Button quitb; // Quit button.
Button clearb1, clearb2; // Two clear buttons.
Canvas c1, c2; // Two canvases.
Panel p1, p2; // One panel per canvas.
Panel outerpanel; // A panel to contain p1, p2.
int
c1_current_x=0, // Current mouse-click position
c1_current_y=0, // for canvas 1.
c2_current_x=0,
c2_current_y=0; // Same for canvas 2.
// Constructor.
public NewFrame (int width, int height)
{
// Set the title and other frame parameters.
this.setTitle ("Two canvas example");
this.setResizable (true);
this.setBackground (Color.cyan);
this.setSize (width, height);
// this.setLayout (new BorderLayout());
// Create a quit button for the whole frame.
quitb = new Button ("Quit");
quitb.setBackground (Color.red);
quitb.setFont (new Font ("Serif", Font.PLAIN | Font.BOLD, 15));
quitb.addActionListener (this);
this.add (quitb, BorderLayout.SOUTH);
// Create a Panel for the first canvas
p1 = new Panel ();
p1.setLayout (new BorderLayout());
// Create a white canvas.
c1 = new Canvas ();
c1.setBackground (Color.white);
c1.setForeground (Color.blue);
c1.addMouseListener (this);
// Add canvas to frame in the center.
p1.add (c1, BorderLayout.CENTER);
// Create a clear button.
clearb1 = new Button ("Clear");
clearb1.addActionListener (this);
clearb1.setBackground (Color.green);
p1.add (clearb1, BorderLayout.NORTH);
// Create a Panel for the second canvas.
p2 = new Panel ();
p2.setLayout (new BorderLayout());
// Create a second white canvas.
c2 = new Canvas ();
c2.setBackground (Color.white);
c2.setForeground (Color.blue);
c2.addMouseListener (this);
// Add canvas to frame in the center.
p2.add (c2, BorderLayout.CENTER);
// Create a second clear button.
clearb2 = new Button ("Clear");
clearb2.addActionListener (this);
clearb2.setBackground (Color.green);
p2.add (clearb2, BorderLayout.NORTH);
// A panel to hold the smaller panels.
outerpanel = new Panel ();
// Use 1-row, 2-column grid with 5-pixel gaps.
outerpanel.setLayout (new GridLayout (1,2,5,5));
outerpanel.add(p1);
outerpanel.add(p2);
// Now add the panel to the frame.
this.add (outerpanel, BorderLayout.CENTER);
// Show the frame.
this.setVisible (true);
}
// This method is required to implement the
// ActionListener interface.
public void actionPerformed (ActionEvent a)
{
// Get the button string.
String s = a.getActionCommand();
if (s.equalsIgnoreCase ("Quit"))
System.exit(0);
else if (s.equalsIgnoreCase ("Clear")) {
// Need to find out which canvas:
if (a.getSource() == clearb1) {
c1.setBackground (Color.white);
c1.repaint ();
c1_current_x = c1_current_y = 0;
}
else {
c2.setBackground (Color.white);
c2.repaint ();
c2_current_x = c2_current_y = 0;
}
}
}
// These methods are required to implement
// the MouseListener interface.
public void mouseClicked (MouseEvent m)
{
int x = m.getX();
int y = m.getY();
// Need to figure out which canvas:
if (m.getSource() == c1) {
Graphics g = c1.getGraphics();
g.drawLine (c1_current_x, c1_current_y, x, y);
c1_current_x = x;
c1_current_y = y;
}
else {
Graphics g = c2.getGraphics();
g.drawLine (c2_current_x, c2_current_y, x, y);
c2_current_x = x;
c2_current_y = y;
}
}
// We need to implement these methods, but
// don't actually have to do anything inside.
public void mouseEntered (MouseEvent m) {}
public void mouseExited (MouseEvent m) {}
public void mousePressed (MouseEvent m) {}
public void mouseReleased (MouseEvent m) {}
} // End of class "NewFrame"
public class TwoCanvas {
public static void main (String[] argv)
{
NewFrame nf = new NewFrame (300, 200);
}
}
public void actionPerformed (ActionEvent a)
{
// ...
if (a.getSource() == clearb1) {
// ...
}
(Instead of being in the same actionPerformed() method.)
Here is an implementation using local classes for button-listeners:
(source file)
// Constructor.
public NewFrame (int width, int height)
{
// Set the title and other frame parameters.
this.setTitle ("Two canvas example");
this.setResizable (true);
this.setBackground (Color.cyan);
this.setSize (width, height);
// this.setLayout (new BorderLayout());
// Create a quit button for the whole frame.
quitb = new Button ("Quit");
quitb.setBackground (Color.red);
quitb.setFont (new Font ("Serif", Font.PLAIN | Font.BOLD, 15));
// Create a local class. QuitActionListener is our name.
class QuitActionListener implements ActionListener {
public void actionPerformed (ActionEvent a)
{
System.exit(0); // Action required for quit.
}
}
// Create an instance of the local class
// and pass it to the button.
quitb.addActionListener (new QuitActionListener());
// Now add the quit button to the frame.
this.add (quitb, BorderLayout.SOUTH);
// Create a Panel for the first canvas
p1 = new Panel ();
p1.setLayout (new BorderLayout());
// Create a white canvas.
c1 = new Canvas ();
c1.setBackground (Color.white);
c1.setForeground (Color.blue);
c1.addMouseListener (this);
// Add canvas to frame in the center.
p1.add (c1, BorderLayout.CENTER);
// Create a clear button.
clearb1 = new Button ("Clear");
clearb1.setBackground (Color.green);
// First create a listener class.
class ClearActionListener1 implements ActionListener {
public void actionPerformed (ActionEvent a)
{
c1.setBackground (Color.white);
c1.repaint ();
c1_current_x = c1_current_y = 0;
}
}
// Pass an instance of the class to the button.
clearb1.addActionListener (new ClearActionListener1());
// Now add the button to the panel.
p1.add (clearb1, BorderLayout.NORTH);
// Create a Panel for the second canvas.
p2 = new Panel ();
p2.setLayout (new BorderLayout());
// Create a second white canvas.
c2 = new Canvas ();
c2.setBackground (Color.white);
c2.setForeground (Color.blue);
c2.addMouseListener (this);
// Add canvas to frame in the center.
p2.add (c2, BorderLayout.CENTER);
// Create a second clear button.
clearb2 = new Button ("Clear");
clearb2.setBackground (Color.green);
// Define a local class for the second button
class ClearActionListener2 implements ActionListener {
public void actionPerformed (ActionEvent a)
{
c2.setBackground (Color.white);
c2.repaint ();
c2_current_x = c2_current_y = 0;
}
}
// Pass an instance to the (second) clear button.
clearb2.addActionListener (new ClearActionListener2());
// Add the button to panel p2.
p2.add (clearb2, BorderLayout.NORTH);
// A panel to hold the smaller panels.
outerpanel = new Panel ();
outerpanel.setLayout (new GridLayout (1,2,5,5));
outerpanel.add(p1);
outerpanel.add(p2);
// Now add the panel to the frame.
this.add (outerpanel, BorderLayout.CENTER);
// Show the frame.
this.setVisible (true);
}
class NewFrame extends Frame implements MouseListener {
// ...
// Constructor.
public NewFrame (int width, int height)
{
// ...
// Create a local class. QuitActionListener is our name.
class QuitActionListener implements ActionListener {
public void actionPerformed (ActionEvent a)
{
System.exit(0); // Action required for quit.
}
}
// ...
}
}
// Create an instance of the local class
// and pass it to the button.
quitb.addActionListener (new QuitActionListener());
class ClearActionListener1 implements ActionListener {
public void actionPerformed (ActionEvent a)
{
c1.setBackground (Color.white);
c1.repaint ();
c1_current_x = c1_current_y = 0;
}
}
Note:
class NewFrame extends Frame {
// ...
// Constructor.
public NewFrame (int width, int height)
{
// ...
// Create a MouseListener class:
class CanvasMouseListener1 implements MouseListener {
public void mouseClicked (MouseEvent m)
{
int x = m.getX();
int y = m.getY();
Graphics g = c1.getGraphics();
g.drawLine (c1_current_x, c1_current_y, x, y);
c1_current_x = x;
c1_current_y = y;
}
// These methods need to be implemented
// to complete the interface.
public void mouseEntered (MouseEvent m) {}
public void mouseExited (MouseEvent m) {}
public void mousePressed (MouseEvent m) {}
public void mouseReleased (MouseEvent m) {}
}
// Pass an instance of the listener to canvas c1.
c1.addMouseListener (new CanvasMouseListener1());
// ...
}
}
- we should be able to use two instances of the same class.
(Point is a class in AWT).
class NewFrame extends Frame {
// Data.
Button quitb;
Button clearb1, clearb2;
Canvas c1, c2;
Panel outerpanel, p1, p2;
Point c1_current = new Point (0,0); // Point instances.
Point c2_current = new Point (0,0);
// NewFrame Constructor.
public NewFrame (int width, int height)
{
// ...
// Create a generic MouseListener class for both canvases.
class CanvasMouseListener implements MouseListener {
// Data.
Canvas c; // Store which canvas.
Point current; // Store current click position.
// Constructor.
public CanvasMouseListener (Canvas c, Point current)
{
this.c = c; this.current = current;
}
// Handle a mouse click.
public void mouseClicked (MouseEvent m)
{
int x = m.getX();
int y = m.getY();
Graphics g = c.getGraphics();
g.drawLine (current.x, current.y, x, y);
current.x = x;
current.y = y;
}
// Empty methods - to complete interface.
public void mouseEntered (MouseEvent m) {}
public void mouseExited (MouseEvent m) {}
public void mousePressed (MouseEvent m) {}
public void mouseReleased (MouseEvent m) {}
} // End of "CanvasMouseListener"
// Create an instance, passing c1 stuff to the constructor.
c1.addMouseListener (new CanvasMouseListener(c1, c1_current));
// ...
// Create a generic listener class for both clear buttons.
class ClearActionListener implements ActionListener {
// Data.
Canvas c; // Which canvas.
Point current; // The current point of that canvas.
// Constructor.
public ClearActionListener (Canvas c, Point current)
{
this.c = c; this.current = current;
}
// Handle the button-press.
public void actionPerformed (ActionEvent a)
{
c.setBackground (Color.white);
c.repaint ();
current.x = current.y = 0;
}
} // End of "ClearActionListener"
// Create an instance for canvas c1.
clearb1.addActionListener (new ClearActionListener(c1, c1_current));
// ... create the second canvas and clear button ...
// Add a new instance of the MouseListener.
c2.addMouseListener (new CanvasMouseListener(c2, c2_current));
// Pass a new instance of the action listener.
clearb2.addActionListener (new ClearActionListener(c2, c2_current));
// ...
}
// ...
}
Recall that, even though we only wanted to handle mouseClicked
we still had to provide (empty) implementations for
other mouse methods like mouseDragged:
The package java.awt.event provides special
"adapter" classes to relieve this effort:
class CanvasMouseListener implements MouseListener {
// ...
public void mouseClicked (MouseEvent m)
{
// ...
}
// Empty methods - to complete interface.
public void mouseEntered (MouseEvent m) {}
public void mouseExited (MouseEvent m) {}
public void mousePressed (MouseEvent m) {}
public void mouseReleased (MouseEvent m) {}
}
// Create a MouseListener class:
class CanvasMouseListener extends MouseAdapter {
// Data.
Canvas c;
Point current;
// Constructor.
public CanvasMouseListener (Canvas c, Point current)
{
this.c = c; this.current = current;
}
// Handle a mouse click.
public void mouseClicked (MouseEvent m)
{
int x = m.getX();
int y = m.getY();
Graphics g = c.getGraphics();
g.drawLine (current.x, current.y, x, y);
current.x = x;
current.y = y;
}
// Don't need to implement these anymore.
// public void mouseEntered (MouseEvent m) {}
// public void mouseExited (MouseEvent m) {}
// public void mousePressed (MouseEvent m) {}
// public void mouseReleased (MouseEvent m) {}
} // End of "CanvasMouseListener"
(We would not be able to do this with NewFrame
since it already extends Frame).
Recall the listener for the "quit" button defined earlier:
Here, we defined a class and used it only once, wasting
a name.
Java provides the ability to define a class right where it's
needed - in creating an instance:
(source file)
Note:
Exercise 10.1
(Solution):
Recall that we implemented an Enumeration for
linked lists by having the linked list class implement the
Enumeration interface:
class NewFrame extends Frame {
// ...
// Constructor.
public NewFrame (int width, int height)
{
// ...
// Create a local class for the quit button.
class QuitActionListener implements ActionListener {
public void actionPerformed (ActionEvent a)
{
System.exit(0);
}
}
// Pass an instance to the button.
quitb.addActionListener (new QuitActionListener());
// ...
}
}
class NewFrame extends Frame {
// ...
// Constructor.
public NewFrame (int width, int height)
{
// ...
// Using an anonymous class:
quitb.addActionListener (
new ActionListener() {
public void actionPerformed (ActionEvent a)
{
System.exit(0);
}
}
);
// ...
}
}
quitb.addActionListener (
// This is the parameter of addActionListener:
new ActionListener() // A new instance of ActionListener.
// This is the body of the class:
{
public void actionPerformed (ActionEvent a)
{
System.exit(0);
}
}
); // End of parameter list.
c.addMouseListener (
new MouseAdapter () {
public void mouseClicked (MouseEvent m)
{
int x = m.getX();
int y = m.getY();
Graphics g = c.getGraphics();
g.drawLine (current_x, current_y, x, y);
current_x = x;
current_y = y;
}
}
);
In this exercise, change the above code
so that LinkedList does not implement Enumeration.
Instead, in the method get_enumeration, create an
anonymous class that does the job right in the return
statement.
public interface Enumeration {
public abstract boolean hasMoreElements();
public abstract Object nextElement();
}
class LinkedList implements Enumeration {
// ...
public boolean hasMoreElements ()
{
// ...
}
public Object nextElement()
{
// ...
}
public Enumeration get_enumeration ()
{
// ...
}
} // End of class "LinkedList"
For completeness,
we will now consider the remaining two kinds of inner classes:
We will present the material via examples:
Both of these have behavior that can be difficult to understand.
If possible, avoid using them.
class A {
// A static member class.
static class B {
int x; // Data.
public B (int i) { // Constructor.
x = i;
}
public void print () // A method.
{
System.out.println ("B: x=" + x);
}
}
}
public class TestStaticLocal {
public static void main (String[] argv)
{
// Create an instance of B.
A.B b = new A.B (1);
b.print(); // Prints "1".
// Create another instance of B.
A.B b2 = new A.B (2);
b2.print(); // Prints "2".
}
}
class A {
class B {
int x; // Data.
public B (int i) { // Constructor.
x = i;
}
public void print () // A method.
{
System.out.println ("B: x=" + x);
}
}
}
public class TestLocal {
public static void main (String[] argv)
{
A.B b = new A.B (1); // Does not compile.
b.print();
}
}
class A {
// Instance data in A
int y;
// Constructor for A.
public A (int y)
{
this.y = y;
}
// Instance member class:
class B {
int x; // Data.
public B (int i) { // Constructor.
x = i;
}
public void print () // A method.
{
System.out.println ("B: x=" + x + ", y=" + y);
}
}
}
public class TestLocal2 {
public static void main (String[] argv)
{
// Create an instance of A first.
A a = new A (1);
// Now create an "associated" instance of B.
// Note the strange syntax!
A.B b = a.new B (2);
b.print(); // Prints "B: x=2, y=1"
}
}