Events 
Peter Komisar    ©   Conestoga College    latest  version. 6.1 / 2010


The Delegation Event Model



Today, creating visual interfaces are an intrinsic part of
computer programming. Applications require ways of
converting user actions such pressing a button or adjusting
a scrollbar, into meaningful responses. As an example when
a user clicks a SAVE menu button the program needs to take
an appropriate response, such as writing to file or popping up
a file dialog box.  

Components generate events asynchronously and require
an event-driven model to process their activities. Since
the introduction of JDK 1.1, Java has used the 'delegation
event model' to handle events.

delegation  -  an implementation mechanism in which an object
forwards or
delegates a request to another object. The delegate
carries out the request
on behalf of the original  object.
                         
                                             
-'Design Patterns'  E. Gamma et al.


A More Complete Picture Is Found in the JavaBean Component Model

A standard presentation of the 'off-the-shelf', AWT Event
Model
ignores 'under the hood' programming details that
are part of the
overall JavaBean component model.

When a visual component is studied as an example of
the JavaBean architec
ture, it is shown how a source bean
keeps track of it's listeners in a list, issues events and
calls action methods
on these registered listener objects.

These extra details are well hidden in the component design
and are not necessary in learning how to use Java's
visual
components effectively. There is plenty to  cover without
looking 'under the hood at the 'engine'.


Threads and Event Handling



GUI aka the AWT Thread

Event-handling and painting code execute in the event-
dispatching thread which is
also called the GUI or AWT
thread. This
thread loops repeatedly, listening for new
events which it intercepts from the underlying windowing
system. Waiting causes the thread to 'block', ( suspending
itself so as not to waste CPU cycles).

Using a single thread for event dispatching ensures each
event handler will finish before the next one executes.
While one event-handling method is executing, the
program's visual interface is frozen and won't repaint
or respond to other actions such as a mouse click.


Use New Threads For CPU intensive Tasks

It is for this reason that it is recommended that code run
from within an event-handling method should not be too
time-consuming. If need be, a new thread should be
spawned to accomplish a time intensive task allowing
the event thread to resume it's painting and event
processing duties.

// execute time-intensive processes in a new thread


Sources, Event Objects & Listeners



The Source -
When a source component is activated, an
event object is created, encapsulating information which
describes the type of event it is and which component was
responsible for it's generation.

Depending on the component type that generated the event
object, different bits of information are wrapped into the object
in addition to recording which component generated the event.

This data is used to track an event back to the component
that generated it so an appropriate response can be provided.

Source Activation

Source Activated
// button click
    -- generates --> an Event Object
 // Action Event 



Listener Object
- processes event ->  creates Response



The Listener
- Listener classes listen for the events that
are generated by source
components. Java classes become
listeners by implementing one
or more event listener interfaces.
Each listener interface has one or more methods, for which
the programmer must provide an implementation. The methods
respond to events generated by source components.


Listener Interface Form

XXXListener  // for example ItemListener


Registration

Listeners need to be registered with the source component.
The source component maintains a list of of the listener objects
and calls the methods on them whenever the source component
is activated and an event is generated.

A method of the form addXXXListener( ) is used to register
listeners with event source components.

Example  

EventSource source = new EventSource( );
source.addEventListener(EventListener);

// registering a listener with an event source


Listener Interface Methods     // where responses are defined

Listener interface methods take event objects as arguments
and then process their information in conjunction with supplying
a response.

These methods all have a similar design. They are all public
and return void. Each takes the appropriate type of
Event
object which the listener interface was designed to listen for.


Listener Interface Methods

Events

When a  button is clicked or an 'Enter' key is pressed after
some text has been entered into a text field,  an event object
is created by
the component.

In the case of a button or text field the particular type of object
that is created is an instance of the ActionEvent class. Different
component types generate different sorts of events.

 

Example


As mentioned abovie, the event object will carry information
pertinent to which
component created it. For instance a
MouseEvent object will carry the 'x' and
'y' coordinates
where the mouse was clicked. When a button is clicked,
which
button was clicked, is included in the event information
along with whatever text
was used to label the button. We will
see that both these pieces of information then can be used
to
differentiate which of potentially many event sources may have
been activated.


Examples of Different Components Generate Different Sorts of Events 

Several components generate ActionEvents. For instance when
ENTER has been pressed with textfield or with menu item an
action event is generated. JButton also generates 'action'
events when clicked. In addition JButton generates a 'change'
event, a new type of event introduced with the Swing package.
This event is fired when the mouse is 'rolled over' the button
component.

ScrollBars create AdjustmentEvents. Container frames generate
Window events. The following sections include tables describing
the different AWT components and which events they generate.


Example of a Listener Interface Implementation

As an example, ActionEvent objects are listened for by classes
implementing the ActionListener interface. The ActionListener
interface defines one method that the implementing class must
provide an implementation for,  as shown in the following example.


Example   

public class ThisListener implements ActionListener{ 
          public void actionPerformed(ActionEvent ae) {
            // ActionListenerer's method used to responsd
           // to component activation

                     }
                 }

The above example shows the Listener interface being
implemented along with an implementation of it's one
required method. The method takes the event and is
used to provide a response.



The Java Event Processing Classes



Practically speaking, we may now look at the actual classes
that
are used in the roles described in the event model above.

 
Event Packages   // java.awt.event.*

To process events, the appopropriate event package needs
to be imported. The java.awt.event package contains a set of
commonly used events. All the classic,
AWT events also work
with Swing components.  Additional events have been added

with new Swing package and are located in the javax.swing.event
package. The AWT event package can
be brought into an
application using the following import statement.


Example

import java.awt.event.*;

If one of the newer Swing events will be used the Swing event
package may
be imported. These new event types include the
earlier mentioned ChangeEvent
and HyperLinkEvent. The new
events are providing to support new capabilities
introduced
with the new Swing components. The following import may be
necessary when new Swing events are used.

Example    

import javax.swing.event.*;

// newer Swing events include ChangeEvent & HyperLinkEvent

Event Model Syntax

The following naming patterns facilitate the use of the event
package derives from
nomenclature created for JavaBeans
which AWT and Swing components are all examples
of. Here
for simplicity the AWT actions are listed but the new Swing
events that have been
added follow the same naming pattern.


The Classic AWT Event Types


Action
Adjustment
Container
Component
Focus
Item
Key
Mouse
MouseMotion
Text
Window


The names of listeners corresponding to these event types
are created by adding
the suffix Listener to the particular
action name.


Example  

Mouse + Listener = MouseListener


The name of each event class can be derived by adding
the suffix Event to the action
name.


Example  

Adjustment + Event = AdjustmentEvent


The AWT Event Listener Interfaces

The AWT event package contains listener interfaces along
with a set of listener
adapter classes and the different event
classes. The following table shows the
listeners of the AWT
event package.

The following table lists the Listeners along with a description
of what events they process and which components serve as
sources for those events. Notice all the listeners follow the
XXXListener naming syntax.


 Interfaces 

 The Listener's Purpose

 Event Sources

 ActionListener

 accepts action events.

 buttons, menus, text fields

 AdjustmentListener 

 accepts adjustment events. 

 scrolling components i.e. JSlider

 AWTEventListener

AWTEventListeners passively
observes system-wide AWT events.

 most apps wouldn't use this
 listener, for monitoring & testing

 ComponentListener

 accepts component events.

 modifying a component' size,    location or visibility

 ContainerListener

 accepts container events.

 adding or removing a
 component from a container

 FocusListener

 accepts keyboard focus
 events on a component.

 tabbing or requesting focus 
 creates a FocusEvent

 ItemListener

 accepts item events.

 An item selected from a list or
 checkbox creates an ItemEvent

 KeyListener

 accepts keyboard events 

 Keyboard created KeyEvents

 MouseListener

accepts mouse events (press,  release, click, enter and exit)
on a component.

 The mouse creates
 a MouseEvent

MouseMotionListener 
 accepts events created when
mouse is moved or dragged
 Mouse creates a MouseMotionEvent

 TextListener

 accepts text events.

 Text input controls

 WindowListener

 accepts window events.

 i.e. like closing a window



The Listener Methods

The following table shows the methods that each listener interface
specifies. These are the set of methods that need to be overridden
when a given interface is being implemented.

Note the four interfaces with single methods are highlighted. (They
do not have adapter classes which are explained in a moment.)


Example
   

adjustmentValueChanged( AdjustmentEvent )


Listener Interfaces with Methods  // Single Method Interfaces highlighted

 

Listener Interface

Interface methods

Adapter class

ActionListener

actionPerformed (ActionEvent)

         ~

AdjustmentListener

adjustmentValueChanged
(AdjustmentEvent)

         ~ 

ComponentListener

componentHidden(ComponentEvent)
componentMoved(ComponentEvent)
componentResized(ComponentEvent)
componentShown(ComponentEvent)

 ComponentAdapter

ContainerListener

componentAdded(ContainerEvent)
componentRemoved(ContainerEvent)

 ContainerAdapter

FocusListener

focusGained(FocusEvent)
focusLost(FocusEvent)

 FocusAdapter

ItemListener

itemStatedChanged(ItemEvent)

         ~ 

KeyListener

keyPressed(KeyEvent)
keyReleased(KeyEvent)
keyTyped(KeyEvent)

 KeyAdapter 

MouseListener 

mouseClicked(MouseEvent)
mouseEntered(MouseEvent)
mouseExited(MouseEvent)
mousePressed(MouseEvent)
mouseReleased(MouseEvent)

 MouseAdapter

MouseMotionLinstener

mouseDragged(MouseEvent)
mouseMoved(MouseEvent)

 MouseMotionAdapter 

TextListener 

textValueChanged(TextEvent)

        ~

WindowListener 

windowActivated(WindowEvent)
windowClosed(WindowEvent)
windowClosing(WindowEvent)
windowDeactivated(WindowEvent)
windowDeiconified(WindowEvent)
windowIconified(WindowEvent)
windowOpened(WindowEvent)

 WindowAdapter

EventListeners Added in JDK 1.4

HierarchyBoundsListener ancestorMoved(HierarchyEvent e)
ancestorResized(HierarchyEvent e)
HierarchyBoundsAdapter
HierarchyListener
hierarchyChanged(HierarchyEvent e)
                  ~



Adapter Classes // stub implementations

Along with methods, the above table also lists 'Adapter Classes'.
Listener interfaces that have
more than one method have adapter
class counterparts. They have the following naming scheme.

Adapter Class Naming Scheme

XXXAdapter          

 // where XXX is the type of component listener being adapted


Adapter classes have empty, stub definitions for all the methods
in similarly named interface classes. Using an adapter class
eliminates the need for providing implementations for methods
that are needed.

Because adapters are classes, they are extended rather than
implemented.

In the first example below one WindowListener method is
implemented and the rest are stubbed out.  The next example
shows WindowListener's Adapter class used to eliminate the
need to supply stub methods.

Implementing Listener and Stubbing Out Unused Methods

import java.awt.*;
import java.awt.event.*;

class Windower implements WindowListener{

public void windowActivated(WindowEvent we){
     // do something significant to the program
    }
// all the other methods are stubbed out
public void windowClosed(WindowEvent we){ }
public void windowClosing(WindowEvent we){ }
public void windowDeactivated(WindowEvent we){ }
public void windowDeiconified(WindowEvent we){ }
public void windowIconified(WindowEvent we){ }
public void windowOpened(WindowEvent we){ }
}


Extending Window Adapter

import java.awt.*;
import java.awt.event.*;

class WindowEZ extends WindowAdapter{
public void windowActivated(WindowEvent we){
     // do something significant to the program
    }
 }
 // other WindowListener methods are stubbed out for you
 



No Benefit to Having Adapters for Single Method Interfaces


It is obvious, there is no economic benefit to supplying an
adapter class for a listener interface that only has a single
method. Accordingly, while there are 11 listeners in the
AWT Event package, only 7 adapter classes defined.


Debugging Adapter Classes

The use of Adapter classes can lead to a subtle debugging
problem. You need to keep in mind that you are overriding a
perfectly functional empty method. If you don't override the
given method exactly ( i.e. make a spelling mistake ), you
in effect create a new method which is overlooked when
the action occurs, and the empty method is invoked instead.

The net result is code which compiles and runs but doesn't
work. The following example shows perfectly functional code
that will not provide the desired response ot a given action.

This might happen to a programmer migrating from MS .NET
where the convention, opposite to Java,  is to capitalize method
names.


Broken Use of a Adapter Class
// method's first letter is in caps, and so does not override stub,
// do nothing stub is invoked

import java.awt.*;
import java.awt.event.*;

class WindowOZ extends WindowAdapter{
public void WindowActivated(WindowEvent we){
     // do something significant to the program
    }
 }
// override should be on 'windowActivated', lower case 'w'

The next table shows the Event classes and the Adapter
classes listed as a group. All the event classes in the event
\package extend the root event class java.util.EventObject.


Event & Adapter Classes of the AWT event package

 

 Event Classes

 

 ActionEvent

 A semantic event indicating a component-defined action
 has occurred

 AdjustmentEvent

 The adjustment event emitted by adjustable objects.

 ComponentEvent

 A low-level event which indicates that a component moved, changed size, or changed visibility (the root class for the
other component-level events)

 ContainerEvent

 A low-level event which indicates that a container's contents changed because a component was added or removed.

 FocusEvent

 A low-level event which indicates that a component has
 gained or
lost the keyboard focus.

 InputEvent

 The root event class for all component-level input events.

 InputMethodEvent

 Input method events contain information about text that is
 being
composed using an input method.

 InvocationEvent

 An event which executes the run( ) method on a Runnable
 when
dispatched by the AWT event dispatcher thread.

 ItemEvent

 A semantic event which indicates that an item was
 selected or deselected.

 KeyEvent

 An event which indicates that a keystroke occurred in a component.

 MouseEvent

 An event which indicates that a mouse action occurred
 in a component.

MouseMotionEvent
 An event created when mouse is dragged or moved

 PaintEvent

 The component-level paint event.

 TextEvent

 A semantic event indicating that an object's text changed.

 WindowEvent

 A low-level event which indicates that a window has
 changed its status.

 Adapter Classes


 ComponentAdapter

 An abstract adapter class for receiving component events.

 ContainerAdapter

 An abstract adapter class for receiving container events.

 FocusAdapter

 An abstract adapter class for receiving keyboard focus events.

  KeyAdapter

 An abstract adapter class for receiving keyboard events.

 MouseAdapter

 An abstract adapter class for receiving mouse events.

 MouseMotionAdapter

 An abstract adapter class for receiving mouse motion events.

 WindowAdapter

 An abstract adapter class for receiving window events.


The following insert distinguishes 'semantic events' from 'low-level' events.

Semantic v.s. Low Level Events
// the micro edition calls them High vs Low Level Events


There are four so called semantic events. Theses are the action, adjustment, item and text events. These event types are defined in terms of other lower-level events. There are seven low-level events. They are the component, key, mouse, mouse motion, focus, window and container events. For example, Clicking on a button is really based on mouse events and is thus a 'semantic' event.

 // The semantic event types have the single method listeners


E
vent Class Details & Important Methods  

EventObject

All event  classes derive from EventObject. EventObject descends
directly
from Object class. EventObject defines just two methods.
It override's the toString( )
method provided by Object class and
supplies the getSource( ) method that returns
a reference to the
component that generated the event. How EventObject is related

to ActionEvent is shown in the diagram below.


The getSource( )  Method

The getSource(  ) method is important in event processing as it is
used to reference the component
that was the source for a given
event.
The method returns a reference to the component from which
the event came

 

AWTEvent

AWTEvent descends from EventObject. Among other methods the
class provides getID( ) which returns an int value representing the
ID of an event.
The event's ID specifies the nature of the event that
has occurred.


AWT Event Class Hierarchy

 java.lang.Object
          |
         +--java.util.EventObject
                |
               +--java.awt.AWTEvent
                      |
                     +--java.awt.event.ActionEvent
 

The method getID( ) returns the same int value held by event
constants such as
MouseEvent.MOUSE_ENTERED.


For Reference

AWTEvent also defines a number of 'masks' that provide another way to process events using the Component enableEvents( ) method. The masks are used internally by the AWT API to differentiate event types.

We used this technique with AWT components but found they didn't work with Swing. (rechecked in   02/2010). Perhaps they work now. The code remains in the
supplemental at the end of the note




ActionEvent

ActionEvent derives from AWTEvent which in turn descends from
EventObject. ActionEvent is one of the 'high-level', semantic events.
The event is passed to the list of ActionListener objects registered
to receive ActionEvents. Following are summaries of ActionEvent
constructors and methods. Notice the ActionEvent constructors both
take a reference to the object that is the source of the event object.

// defines the important method getActionCommand( )

Following is a table summary of the ActionEvent members.


ActionEvent Constructor Summary

 

ActionEvent (Object source, 
 int id, String command) 

Constructs an ActionEvent object.

ActionEvent(Object source, int id, 
  String command, int modifiers) 

Constructs an ActionEvent
 object with modifier keys.


ActionEvent Method Summary

 

String 
getActionCommand( )

Returns the command string associated
with this action.

 int getModifiers( ) 

Returns the modifier keys held down during
this action event.

String
paramString( ) 

Returns a parameter string identifying this
action event.



getActionCommand( )

The above table shows ActionEvent defines another key method,
getActionCommand( )
which provides alternative way of determining
where an event originated from. This method determines what
component that it comes from based on text that was associated
with the component. This can be useful to identify a source where
no reference is available for the source.


setActionCommand( )

The setActionCommand( ) method can be used to set an action
command for a component, in which case the text associated
with a component's view can be different. In the event that the
action command is not set, the default becomes the text associated
with the constructor or the settText() method.

In the following example, though no reference to the button is
captured, the object can be referenced by it's associated text "X".


Example

add( new Button("X" ));

// has no reference but getActionCommand( ) can
// be used
to identify the button with text value "X"


MouseEvent

A few details of one other Event classes, MouseEvent deserve
mentioning. MouseEvent is two generations deeper in specialization
than ActionEvent. The extra work on the class is needed to make
available additional information that is available with mouse events.
Following is a diagram that positions Mouse event in the hierarchy
of Event classes.


Event Hierarchy Leading to MouseEvent

  java.lang.Object
       |
      +--java.util.EventObject
             |
            +--java.awt.AWTEvent
                   |
                  +--java.awt.event.ComponentEvent
                          |
                         +--java.awt.event.InputEvent
                                |
                               +--java.awt.event.MouseEvent
 

The creation of a MouseEvent object indicates a mouse action
has occurred in a component. This event type is used to represent
both mouse type events such as clicks, enter and exit. It also is
used for mouse motion events which describe 'moves' and 'drags'.

The way the model works is the same for all the action types. A
MouseEvent object is passed as an argument to the listener
methods of listeners registered to receive mouse events. This 
registration is achieved using the addMouseListener method.
A similar pattern is following to register MouseMotionListener
objects.

// Check the J2SDK documentation for processing mouse button combinations.


MouseEvent Constructor

MouseEvent constructor takes in a lot of information when it is
created, including
x and y coordinates and whether the associated
component is a pop-up menu.
Following is MouseEvents single
constructor.

MouseEvent Constructor

      MouseEvent (   
                          Component source,

                          int id,
                          long when,
                          int modifiers,
                          int x, int y,
                          int clickCount,
                          boolean popupTrigger

                          )

// Constructs a MouseEvent object with the specified source
// component, type, modifiers, coordinates, and click count.

Mouse Event Method Summary
 

 int
getClickCount( ) 

 Return the # of mouse clicks associated with  this event.

 Point getPoint( ) 

 Returns x ,y of the event, relative to the source component in the form of a Point object. (Point has get and set for ints, x & y).

 int getX( ) 

 Returns the horizontal x position of the event relative to the source component.

 int getY( ) 

 Returns the vertical y position of the event relative to  the source component.

 boolean 
 isPopupTrigger( ) 

 Returns if this mouse event is the pop-up menu trigger event for the platform.

 String paramString( ) 

 Returns a parameter string identifying this event.

void  translatePoint
 (int x, int y) 

 Translates the event's coordinates to a new  position by adding specified offsets.



The following code sample shows the the int values
that are returned
with different types of mouse actions.
It also includes the getX( ) and
get( ) methods to show
where in the component the action took place.


Example of int Values Returned with Mouse Events & getX( ), getY( ) Methods

import java.awt.*;
import java.awt.event.*;

class Mouser extends Frame implements MouseListener {
      Mouser(String s){
      super(s);
      addMouseListener(this);
      setSize(600,200);
      setVisible(true);
      // the older way of closing windows
      addWindowListener(new WindowAdapter( ){
      public void windowClosing(WindowEvent e){
       System.exit(0);
       }
       });
      }

public void mouseClicked(MouseEvent me){
System.out.println("Mouse Clicked: " + MouseEvent.MOUSE_CLICKED );
System.out.println("Coordinates of Event: (" + me.getX() +","+me.getY()+ ")");
System.out.println("Event ID : " +  me.getID( )); 
// getID( )  returns same value as is given in constants
}
public void mouseEntered(MouseEvent me){
System.out.println("Mouse Entered: " + MouseEvent.MOUSE_ENTERED);
System.out.println("Coordinates of Event: (" + me.getX() +","+me.getY()+ ")");
}
public void mouseExited(MouseEvent me){
System.out.println("Mouse Exited: " + MouseEvent.MOUSE_EXITED);
System.out.println("Coordinates of Event: (" + me.getX() +","+me.getY()+ ")");
}
public void mousePressed(MouseEvent me){
System.out.println("Mouse Pressed: " + MouseEvent.MOUSE_PRESSED);
System.out.println("Coordinates of Event: (" + me.getX() +","+me.getY()+ ")");
}
public void mouseReleased(MouseEvent me){
System.out.println("Mouse Released: " + MouseEvent.MOUSE_RELEASED);
System.out.println("Coordinates of Event: (" + me.getX() +","+me.getY()+ ")");
}
 
public static void main(String[]args){
new Mouser("Demo of int values returned with mouse events" );
}

}
 



Differentiating Between Event Sources



Sources and listeners can be arranged in 'many-to-one' or
'one-to-many'
relationships. One can have many listeners
notified by the same component or
have many components
notifying the same listener. In the latter case, control
logic is
used to determine which component was activated so
an
appropriate response can be provided.

In the event that a number of buttons use the container as
the listener via the 'this' keyword, determining which button
was activated can be sorted out with the help of an 'if else'
statement or with a switch.

EventObject's getSource( ) method is typically used to return
the reference to the event source. Alternatively, the method
getActionCommand( ) defined in ActionEvent can be used to
return a String object associated with the component.

Key Sourcing Methods

In the case of a button that String will be the text that has been
used to label the button.

The following two examples show both of these techniques.
Notice that the logic to
determine which component has been
activated resides inside the implementation
of the listener
interface action method.


Example Using getSource( ) to Differentiate Source

  public void actionPerformed(ActionEvent ae){
      Object source=ae.getSource( );
        if (source.equals(jb1)){
           j1Text.setText("A character");
          }
       else if (source.equals(jb2))
          j2Text.setText("Another character");
    // etc.
    }
}

Example Using getActionCommand( ) to Differentiate Source

   public void actionPerformed(ActionEvent ae){
       String string = ae.getActionCommand( )
          if ( string.equals( "Name")){
             j1Text.setText( "Your Name");
         else if(e.getActionCommand( ).equals("Address"))
            j2Text.setText("Your Address");
    // etc.
    }
 }


For more complicated selections, a switch statement
might be used.



Practical Steps To Processing Events in Java

The steps that need to be taken  to use Java's event
model can be summarized as follows.

Event Processing Steps

1) Create a listener class by implementing a listener interface

2) Create a component which will generate an event

3) Instantiate the listener class  // a new instance

4) register the listener with the source component using
it's  addXXXListener( ) method. Pass
the listener class
object that will provide the response to the action to the
addXXXListener( ) method.

In the next section we provide a number of variations on
deploying Java's delegation event model. In everycase,
the steps described above will always need to be taken.



Variations On Adding Listeners to Components



1. An external class listens for a component events

The first approach we look at is for an externally defined class
to do the listening. Here you can see all the pieces you need
to process events. The ClassicListener class implements the
listener interface and supplies an implementation for the method
the listener interface defines. The listener is then instantiated
and the newly formed object is registered with the source
component using the addActionListener( ) method. ( The
second example includes a complete code example that
can be run.)

Example

      //  inside a class extending JFrame or JApplet
                JButton b=new JButton("class");
                ClassicListener c=newClassicListener( ); *
                b.addActionListener(c);
            //  . . .

        class ClassicListener implements ActionListener{
                  public void  actionPerformed (ActionEvent ae){
                  System.out.println("classic action invocation");
                  }
              }

This design has some limitation. For instance a listener created
outside the constructor of the GUI, the listener method won't have
references to the components inside the GUI. This may be OK for
a printer however this wouldn't be good if a calculation was being
done and needed to be shown in the GUI.

One way to remove this limitation is to define a listener with a
constructor that takes as arguments the components you wish to
notify when a listener's method has been activated.


Example

import javax.swing.*;
import java.awt.event.*;
import java.awt.*;

class LisVar extends JFrame{
        LisVar( ){
       JButton b=new JButton("class");
       JTextField jt=new JTextField("yes" );
       ClassicListener c=new ClassicListener( jt,"no" );
       b.addActionListener(c);
       getContentPane().add(jt);
       getContentPane().add(b, BorderLayout.NORTH);
       setSize(400,300);
       setVisible(true);
       }
       public static void main(String[]args){
       new LisVar();
       }
    }

  class ClassicListener implements ActionListener{
            String s;
            JTextField jt;
         public ClassicListener(JTextField jt, String s){
            this.s=s;
            this.jt=jt;
            }
         public void actionPerformed (ActionEvent ae){
           System.out.println(s);
           jt.setText(s);
           }
         }

2. The containing class instance listens for events

Making the containing class the listener is the most common
way that events are implemented. It has the advantage of being
simple and straight forward to implement. The downside comes
when too many components are using the container to process
their commands. The code may get unwieldly. Despite this, it is
a convenient approach and is shown in the following example.
The comments in the code point out key features of the process.


Example 1

import java.awt.event.*;
import java.awt.*;
import javax.swing.*;

class Crate extends JFrame implements ActionListener{
         // the container implements the listener
 
       JButton one,two,three,exit;
        Crate( ){

        getContentPane( ).setLayout(new GridLayout(1,4));
        one= new JButton("One");
        two= new JButton("Two");
        three= new JButton("Three");
        exit= new JButton("Exit");

       one.addActionListener(this);
       two.addActionListener(this);
       three.addActionListener(this);
       exit.addActionListener(this);


       // sources register 'this' as the listener

       getContentPane( ).add(one);

       getContentPane( ).add(two);
       getContentPane( ).add(three);
       getContentPane( ).add(exit);
       }

/* The listener method is defined inside 'this' the container */

   public void actionPerformed (ActionEvent ae){
      if (ae.getSource( ).equals(one)){
          System.out.println("It's one");
             }
      if (ae.getSource( ).equals(two)){
            System.out.println("It's two");
            }
      if (ae.getSource( ).equals(three)){
            System.out.println("It's three");
            }
      if (ae.getSource( ).equals(exit)){
            System.out.println("Time to go");
            System.exit(0);
            }  
          } 

public static void main (String [] args){
  Crate crate=new Crate( );
  crate.setSize(700,100);
  crate.setVisible(true);
  }
}

Code Sample Showing the Use of ChangeListener

This second example shows the same approach and is
added to show the new
Swing event type, ChangeEvent.
It is deployed in the same manner as other 
AWT events.
A few notable points, the javax.swing.event package is
imported to make the new Swing event available. Also,
the source component needs to have is 'rollover' property
set to true which can be done using the method,
setRolloverEnabled (true).

// for Swing events the extra import is neccessary

Example 2

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.event.*; // for the change listener

class CButton extends JFrame implements ChangeListener{

        JButton button;
        Color color;
        boolean flag;

      CButton( ){
        flag=true;
        button=new JButton("Button Test");
        button.addChangeListener(this );
        button.setRolloverEnabled(true);
        color=new Color(200,150,175);
        button.setBackground(color);
        getContentPane( ).add(button,BorderLayout.CENTER);
        setSize(400,400);
        setVisible(true);
        }

        public static void main(String[]args){
        new CButton( );
        }

public void stateChanged(ChangeEvent e){
    if(flag==true){
      button.setBackground(color.darker());
      flag=false;
      System.out.println("mouse over darkens the component");
      }
  else {
   button.setBackground(color);
   flag=true;
   System.out.println
   ("Removing the mouse restores it's original color");
   }
 }
}

3.  The component is subclassed to listen to itself

This variation creates a subclass which which then listens
to itself. This allows the component to act as it's own
listener. This might be useful for adding a large number
of components that do very different things.

Example

import java.awt.event.*;
import java.awt.*;

    class SelfAuditButton extends Button implements ActionListener{
              public SelfAuditButton(String label){
                super(label);
                addActionListener(this);
                }
            public void actionPerformed(ActionEvent ae){
                System.out.println("action performed by a self listener");
                }
           }
 

4. An anonymous inner class listens for events

Inner classes were designed to supply short 'inline'
responses to a components activation. The 'anonymous
inner class' is
a relatively complicated code structure
but it's very popular for taking care of actions which can
be described in a line or two. It tightly binds the action
performed with the code which solicits the action.

A common place it is used is to close out a frame and
command line process as in the following. (If you add this
to a frame you either add it as is to the constructor or call
it from the object reference for the frame wherever it is
created, often in the main( ) method.)

Before frame closing methods were introduced, circa JDK
1.3.x, the anonymous inner class was the only way that
could be used to close out a frame. The System.exit( 0 )
is included to close the underlying operating system
process.

Example       

addWindowListener(new WindowAdapter( ){
    public void windowClosing(WindowEvent e){
       System.exit(0);
       }
    });

Note the characteristic ending  });  which results from
having the entire inner class defined as an argument of
the addXXXListener( ) method. Because the inner class
is created via the constructor without being assigned to
a named reference it is anonymous. ( Because this
construction represents an inner class, it can only
reference local variables marked 'final' in higher scopes.)
 

5. Action Processing using AbstractAction class

The next example shows a new and simplified way to
process action events
introduced in  JDK1.3 (a.k.a.
J2SDK 1.3.x ).  A class creation expression is used to
create the
listener which is then registered with the
source component. The class
AbstractAction can also
be extended. This provides a simple mechanism
to
process actions.

Example

    // inside a constuctor somewhere
         JMenu file = new JMenu("File");
         JMenuItem noo = new JMenuItem("New");
         AbstractAction aa=new AbstractAction("New!"){
         public void actionPerformed(ActionEvent ae){
         System.out.println("Boo!");
          }
          };
         noo.addActionListener(aa);
         file.add(noo);
        // . . .


6. UI Delegates Listen As Inner Classes 
// for reference

An important pattern used in Java visual components is
to fashion the controllers as inner classes that serve as
listeners for events. This supplies the autonomous event
processing behaviour that was captured in patterns 3
and 4 above.

The following is an ad hoc example, unrelated to how
Java might use inner classes as listeners, just to show
inner classes acting as listeners.

Example

import java.awt.event.*;
import java.awt.*;
import javax.swing.*;

class OOO extends JFrame {
        OOO( ) {
        Listener listener = new Listener();
        addWindowListener(listener);
        add( new JLabel("A Frame to test Inner Class as Listener"));
        setSize(500,500);
        setVisible(true);
        }
// inner class
class Listener extends WindowAdapter{
  public void windowClosing(WindowEvent we){
      System.exit(0);
      }
   }
  // main

 public static void main(String[] args){
     new OOO();
  }
}


Supplemental: An AWT Technique That Bypasses the Event Listener Model   
// just for reference


Following is a supplemental technique for bypassing the
listener model. When Swing was introduced we found this
method didn't work with Swing components. On investigating
it is because the
Swing components do not implement the
processXXXEvent( )
method so can't be overridden.

(This was the case at least for JTextField and JButton which
we looked at!) Notice this technique should work for the peer-
based Swing components  like
JFrame. 


 Bypass listening and enable the component to process its own events
// works in AWT but still not in Swing  10 / 2010



This is a process called Explicit Event Enabling where a component intercepts it's own event message and processes them skipping the listening phase altogether. Being aware of this technique helps explain why the event mask constants are defined in the Event classes.  In this technique

 
1) a component is subclassed
 
 
2) this component's method, enableEvents( ) is passed
    a constant specific to
the type of event being processed.
   For action events the constant passed 
to enableEvents( )
   is AWTEvent.ACTION_EVENT_MASK. There's one
for
   each type of event. This enables the component subclass
   to process 
action events.

     3) a process method has to be overridden to provide the
      desired response as
well as being called in the parent
      (via super) to obtain the parent class' 
behaviour. In the
      case of an ActionEvent the method is called

 
        proceesActionEvent(ActionEvent ae).

Example

  import java.awt.*;
   import java.awt.event.*;
   import javax.swing.*;

  public class EnableFrame extends JFrame {

       static int count;
 
  public EnableFrame(String title) {
         super(title);
         enableEvents(AWTEvent.WINDOW_EVENT_MASK); 
         EnableText eb=new EnableText("Enabled");
         add(eb);
         //getContentPane( ).add(eb);
        }
  public void processWindowEvent(WindowEvent we) { 

        count++;
       System.out.println("Processing a window event:." + count); 
        super.processWindowEvent(we);
        count=count++;
        }
   public static void main(String args[]){
       JFrame f= new EnableFrame("google" );
       f.setSize(400,300 );
       f.show( );   
       }
   }
 
  class EnableText extends JTextField{
       EnableText( String title){
           super(title);
           enableEvents(AWTEvent.ACTION_EVENT_MASK); 
           }
  public void processActionEvent(ActionEvent ae){
       System.out.println(" Processing the TextField's Action");
       super.processActionEvent(ae);
       }
  }



Self Test                                          Self Test With Answers


1) One thread is dedicated to painting. It is called by several names.
    Which of the following is an unrelated name?

a) Delegation thread
b) Event-dispatching thread
c) GUI thread
d) AWT thread

2) Which of the following houses the methods used to respond to events?
a) Source
b) Listener
c) Event

3) Which of the following is not a characteristic of typical listener interface methods?

a) listener methods may be marked private
b) return values are always void
c) the method name includes the action and an indication of what the method does.
d) Each listener method will takes as an argument a event class object

4) Which of the following is the parent to the others?

a) ComponentEvent
b) MouseEvent
c) AdjustmentEvent
d) AWTEvent

5) Which of the following is used to return the reference for the component
    that was the source of an event?

    a ) getActionCommand( )
    b) getSource( )
    c) getAction( )
    d) getEventSource(  )

6 ) Which of the following is not a semantic event?

a) Action
b) Mouse
c) Text
d) Item
 


Exercise  



1) Create a JFrame.  Create 4 JButtons and put them into a 1 by 4
    GridLayout. Add this panel to the the south section of the JFrame.
    By pushing each of these buttons different sorts of information
    will be supplied to screen. ( Any four will do. For instance,
    store location(s), shipping policy,  refund policy, forms of payment.
    Alternatively, you might describe a product, with labels such as
    Product Model, Description, Options, Price. )
   

a )  Use the JFrame container as the listener for the four buttons. Use
      getSource( ) or getActionCommand( ) to provide an action based
      on what button is pressed. Use System.out.println( ) statements
      to the command line screen to confirm your events are being
      processed correctly.

b)   Add a JTextArea to the center area of the JFrame. Use JTextArea
      setText( ) method to add descriptions associated with each of the
      four buttons to screen.

c ) Make the container a ChangeListener as well. (Multiple interface
     implementations are comma-separated.) Use the ChangeListener
     method to create a 'rollover' effect for the 4 buttons that are being
     added to the bottom of the display.
    

d )  Add an 'anonymous' inner class to implement a WindowListener in
      order to close out the JFrame.


2) Using the following chart as a template, finish the chart for the remaining
ten
AWT event types. This chart collects the information available in the
different
tables found in the note. Using a landscape format may allow
more room and
give better visual results. (Use cut and paste to make
this as easy as possible.)

 

Event Type 

 Interface 

 Adapter

 Event Class

 Sources

Method(s)

 Action

ActionListener

     ~ 

ActionEvent

Button,
 MenuItem
 TextField 

public void
actionPerformed
(ActionEvent ae)