First, what is an event?
Where do you find classes related to events?
Classes related to events:
We have already seen, for example, that a JButton
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?
How to work with events without losing your mind:
Some general information about "event" classes:
Next, a tour of some "listeners":
Note:
(For example, when a user presses a button, you the
programmer may need to perform some computation).
JButton b = new JButton ("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 ...
}
}
);
e.g., "what key was pressed?"
or, "what are the mouse coordinates?"
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 a somewhat contrived (but simple!) example to illustrate:
Here is what we want the frame to look like:
Here is the code:
(source file)
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:
Next, we will make some modifications:
Here is the code:
(source file)
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
class NewFrame extends JFrame
implements ActionListener {
// Data.
JButton quitB; // Quit button.
JButton helloB, worldB; // Two silly buttons.
// Constructor.
public NewFrame (int width, int height)
{
// Set the title and other frame parameters.
this.setTitle ("Two button example");
this.setResizable (true);
this.setSize (width, height);
// We'll use a flowlayout
Container cPane = this.getContentPane();
cPane.setLayout (new FlowLayout());
// Quit button
quitB = new JButton ("Quit");
quitB.setBackground (Color.red);
quitB.addActionListener (this);
cPane.add (quitB);
// "Hello" button
helloB = new JButton ("Hello");
helloB.setBackground (Color.green);
helloB.addActionListener (this);
cPane.add (helloB);
// "World" button
worldB = new JButton ("World");
worldB.setBackground (Color.green);
worldB.addActionListener (this);
cPane.add (worldB);
// Show the frame.
this.setVisible (true);
}
// Need this method for 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 ("Hello")) {
System.out.print ("Hello ");
}
else if (s.equalsIgnoreCase ("World")) {
System.out.println ("World!");
}
}
} // End of class "NewFrame"
public class TwoButton {
public static void main (String[] argv)
{
NewFrame nf = new NewFrame (300, 200);
}
}
(Instead of being in the same actionPerformed() method.)
Here is an implementation using a local class for one of the button-listeners:
(source file)
public NewFrame (int width, int height)
{
// Set the title and other frame parameters.
this.setTitle ("Two button example");
this.setResizable (true);
this.setSize (width, height);
// We'll use a flowlayout
Container cPane = this.getContentPane();
cPane.setLayout (new FlowLayout());
// Quit button
quitB = new JButton ("Quit");
quitB.setBackground (Color.red);
// Local class definition.
class QuitButtonListener implements ActionListener {
public void actionPerformed (ActionEvent a)
{
System.exit (0);
}
}
// Instantiate local class.
QuitButtonListener qListener = new QuitButtonListener();
// Add the listener to the button.
quitB.addActionListener (qListener);
// Finally, add the button to the frame.
cPane.add (quitB);
// "Hello" button
helloB = new JButton ("Hello");
helloB.setBackground (Color.green);
helloB.addActionListener (this);
cPane.add (helloB);
// "World" button
worldB = new JButton ("World");
worldB.setBackground (Color.green);
worldB.addActionListener (this);
cPane.add (worldB);
// Show the frame.
this.setVisible (true);
}
class NewFrame extends JFrame implements ActionListener {
// ...
// 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.
}
}
// ...
}
}
// Instantiate local class.
QuitActionListener qListener = new QuitActionListener();
// Add the listener to the button.
quitB.addActionListener (qListener);
quitb.addActionListener (new QuitActionListener());
class NewFrame extends JFrame {
// Note: Frame does not implement ActionListener anymore
// Data.
JButton quitB; // Quit button.
JButton helloB, worldB; // Two silly buttons.
String helloStr = "Hello ";
String worldStr = "World!";
// Constructor.
public NewFrame (int width, int height)
{
// Set the title and other frame parameters.
this.setTitle ("Two button example");
this.setResizable (true);
this.setSize (width, height);
// We'll use a flowlayout
Container cPane = this.getContentPane();
cPane.setLayout (new FlowLayout());
// Quit button
quitB = new JButton ("Quit");
quitB.setBackground (Color.red);
// Local listener:
class QuitActionListener implements ActionListener {
public void actionPerformed (ActionEvent a)
{
System.exit (0);
}
}
quitB.addActionListener (new QuitActionListener());
cPane.add (quitB);
// "Hello" button
helloB = new JButton ("Hello");
helloB.setBackground (Color.green);
// Listener:
class HelloActionListener implements ActionListener {
public void actionPerformed (ActionEvent a)
{
// Note: we are accessing top-level variable.
System.out.print (helloStr);
}
}
helloB.addActionListener (new HelloActionListener());
cPane.add (helloB);
// "World" button
worldB = new JButton ("World");
worldB.setBackground (Color.green);
// Listener:
class WorldActionListener implements ActionListener {
public void actionPerformed (ActionEvent a)
{
System.out.print (worldStr);
}
}
worldB.addActionListener (new WorldActionListener());
cPane.add (worldB);
// Show the frame.
this.setVisible (true);
}
} // End of class "NewFrame"
class NewFrame extends JFrame {
// ...
String helloStr = "Hello ";
String worldStr = "World!";
public NewFrame (int width, int height)
{
// ...
class HelloActionListener implements ActionListener {
public void actionPerformed (ActionEvent a)
{
// Note: we are accessing top-level variable.
System.out.print (helloStr);
}
}
// ...
}
Note:
Next, we will continue our contrived example by printing
something to System.out when a mouse-click occurs.
Again, we will use a local class:
(source file)
Recall that, even though we only wanted to handle mouseClicked
we still had to provide (empty) implementations for
other mouse methods like mouseDragged:
Java often provides special "adapter" classes to relieve this effort:
public NewFrame (int width, int height)
{
// Set the title and other frame parameters.
this.setTitle ("Two canvas example");
this.setResizable (true);
this.setSize (width, height);
// We'll use a flowlayout
Container cPane = this.getContentPane();
cPane.setLayout (new FlowLayout());
// Quit button
quitB = new JButton ("Quit");
quitB.setBackground (Color.red);
// Local listener:
class QuitActionListener implements ActionListener {
public void actionPerformed (ActionEvent a)
{
System.exit (0);
}
}
quitB.addActionListener (new QuitActionListener());
cPane.add (quitB);
// "Hello" button
helloB = new JButton ("Hello");
helloB.setBackground (Color.green);
// Listener:
class HelloActionListener implements ActionListener {
public void actionPerformed (ActionEvent a)
{
// Note: we are accessing a top-level variable.
System.out.print (helloStr);
}
}
helloB.addActionListener (new HelloActionListener());
cPane.add (helloB);
// "World" button
worldB = new JButton ("World");
worldB.setBackground (Color.green);
// Listener:
class WorldActionListener implements ActionListener {
public void actionPerformed (ActionEvent a)
{
System.out.print (worldStr);
}
}
worldB.addActionListener (new WorldActionListener());
cPane.add (worldB);
// Deal with mouse clicks.
class FrameMouseListener implements MouseListener {
public void mouseClicked (MouseEvent m)
{
System.out.println ("Mouse click!");
}
// 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) {}
}
// Add to frame.
cPane.addMouseListener (new FrameMouseListener());
// Show the frame.
this.setVisible (true);
}
class FrameMouseListener 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) {}
}
// Deal with mouse clicks.
class FrameMouseListener extends MouseAdapter {
public void mouseClicked (MouseEvent m)
{
System.out.println ("Mouse click!");
}
// Don't need these:
// public void mouseEntered (MouseEvent m) {}
// public void mouseExited (MouseEvent m) {}
// public void mousePressed (MouseEvent m) {}
// public void mouseReleased (MouseEvent m) {}
}
(We would not be able to do this with NewFrame
since it already extends JFrame).
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:
Recall that we implemented an Enumeration for
linked lists by having the linked list class implement the
Enumeration interface:
class NewFrame extends JFrame {
// ...
// 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 JFrame {
// ...
public NewFrame (int width, int height)
{
// ...
// Quit button
quitB = new JButton ("Quit");
quitB.setBackground (Color.red);
// Create an implementation right in the method call:
quitB.addActionListener (
new ActionListener() {
public void actionPerformed (ActionEvent a)
{
System.exit (0);
}
}
);
cPane.add (quitB);
// ...
}
} // End of class "NewFrame"
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.
// Deal with mouse clicks.
cPane.addMouseListener (
new MouseAdapter () {
public void mouseClicked (MouseEvent m)
{
System.out.println ("Mouse click!");
}
}
);
In this exercise, change the above code
so that LinkedList does not implement Enumeration.
Instead, in the method getEnumeration, 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 getEnumeration ()
{
// ...
}
} // End of class "LinkedList"
For completeness,
we will now consider the remaining two kinds of inner classes:
We will present the material via examples:
NOTE: Both of these have behavior and syntax 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"
}
}