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.
Today visual interfaces are an intrinsic part of programming. Techniques
are required
to convert signals or messages
generated
by user-activated, virtual components
(i.e.buttons, scrollbars, textfields etc.) into actions performed in
a program. 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.
The standard description of how to use the event
model with off-the-shelf, awt & swing
components leaves out details that arise when
these components are considered in their
JavaBean's context. When a component is studied
as an example of the java bean
architecture, it
is shown how a source bean 1) keeps track of it's listeners, 2) issues
events and3) calls action methods These extra
details are well hidden in the GUI
design and are not neccessary in learning to
use Java's visual components effectively
Threads and Event Handling
Event-handling and painting code executes in the
event-dispatching thread. (a.k.a
the GUI or
AWT thread). This thread loops repeatedly listening for new
events which
it intercepts from the underylying windowing system. Waiting causes
the thread to block,
(suspend 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. It is for this reason
that it is recommended
that the 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.
// If your action code is going
to create a time-intensive process, spawn a new thread to do it
Sources, Event objects & Listeners
When a source component is activated,
an event object is created, encapsulating
information which describes the event and where it came from. For example,
when
a button is clicked an
ActionEvent object is created.
Listener classes listen for events.
Classes become listeners by implementing
one
or more event listener interfaces. Each listener
interface has one or more methods,
for which the programmer provides an implementation which becomes the
response(s)
to the event generated by the component. The listener methods take
event
class
objects
as
arguments (created when the component is activated). The listener
instance is registered with the source component via a method of the
form
SourceComponent source = new SourceComponent(
);
source.addEventListener(EventListener)
For 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.
public class ThisListener extends ActionListener{
public void actionPerformed(ActionEvent
ae) {
// the response to component activation
};
}
Under the hood of a JavaBean as an Event
Source //
for reference
Excerpts from the Magelang Intitute tutorial on JavaBeans available at the Sun Java Developers site. It provides a view how the source code is related to the listener class. The Event Source Classes register themselves
as interested in the event, and they receive notification when
public synchronized void addListenerType(ListenerType l);
In the event source where
these methods are overridden a Vector is used to keep track of
private Vector hireListeners = new Vector( );
If you are using AWT components,
AWT events already have this behavior. Maintaining
protected void notifyHired ( ) {
|
Adapters
Listener interfaces containing more
than one method have 'convenience', counterpart
classes defined called Adapter classes.
Adapter classes have empty or
stub definitions
for all the methods in the sibling interface class.Using adapter class'
eliminates the need
for providing implementations for methods you are not interested in
using.
The form of an abstract vs. an empty or stub method
abstract return_typename(parameter-list);
// An abstract method
ends with a semi-colon and has no
return_typename(
parameter-list){
};
// body while an empty/stub
method has empty curly braces
Debugging Adapter Classes
The use of Adapter classes can lead to a difficult 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
as intended.
Common examples of event dispatching is the creation of an an ActionEvent
instance
when a user, clicks a button hits ENTER in a textfield, iii) selects
a menu item,
iv) double clicks a list item
Syntax formula
The following naming patterns derive from the
nomenclature created for java beans
which awt and swing components are examples of.
The following prefixes describe the classic
awt event types.
Action | Adjustment | Container | Component |
Focus | Item | Key | Mouse |
Text | Window | MouseMotion |
1) adding the suffix Listener
creates the interface name (ie. ActionListener)
2) adding the suffix Event
yields the action event name ie. (ActionEvent)
The java.awt.event Package from
the JDK 1.2.2 API documentation
Interfaces | The Listener's Purpose | Event Sources |
ActionListener | receiving action events. | Buttons, menus, text fields |
AdjustmentListener | receiving adjustment events. | Scrolling components like JSlider |
AWTEventListener | receiving notification of events
dispatched to instances of Component or MenuComponent or their subclasses. |
most apps shouldn't use this
listener |
ComponentListener | receiving component events. | modifying a component |
ContainerListener | receiving container events. | adding or removing a
component from a container |
FocusListener | receiving keyboard focus
events on a component. |
tabbing or requesting focus
creates a FocusEvent |
InputMethodListener | receiving input method events. | Input method events contain info
about text being composed using an input method. When text changes, the input method sends an event. |
ItemListener | receiving item events. | An item selected from a list or
checkbox creates an ItemEvent |
KeyListener | receiving keyboard events | The keyboard creates KeyEvents |
MouseListener | receiving mouse events (press,
release, click, enter, and exit) on a component. |
The mouse creates
MouseMotionEvents |
TextListener | receiving text events. | Text Input Controls |
WindowListener | receiving window events. | i.e like closing a window |
All the event classes in the event package extend the root event class
java.util.EventObject.
Class Summary | // shuffled to seperate the Adapters from the Event classes |
Event Classes | |
ActionEvent | A semantic event indicating a component-defined action has occured |
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. |
PaintEvent | The component-level paint event. |
TextEvent | A semantic event which indicates 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. |
Events are categorized as semantic
and low-level. The semantic events are categorized as action, item and
adjustment types.
Summary of AWT Event Relations
Listener Interface | Event Generated | Interface methods | Adapter class |
ActionListener | ActionEvent | actionPerformed
(ActionEvent) |
~ |
AdjustmentListener | AdjustmentEvent | adjustmentValueChanged
(AdjustmentEvent) |
~ |
ComponentListener | ComponentEvent | componentHidden(ComponentEvent)
componentMoved(ComponentEvent) componentResized(ComponentEvent) componentShown(ComponentEvent) |
ComponentAdapter |
ContainerListener | ContainerEvent | componentAdded(ContainerEvent)
componentRemoved(ContainerEvent) |
ContainerAdapter |
FocusListener | FocusEvent | focusGained(FocusEvent)
focusLost(FocusEvent) |
FocusAdapter |
ItemListener | ItemEvent | itemStatedChanged(ItemEvent) | ~ |
KeyListener | KeyEvent | keyPressed(KeyEvent)
keyReleased(KeyEvent) keyTyped(KeyEvent) |
KeyAdapter |
MouseListener | MouseEvent | mouseClicked(MouseEvent)
mouseEntered(MouseEvent) mouseExited(MouseEvent) mousePressed(MouseEvent) mouseReleased(MouseEvent) |
MouseAdapter |
MouseMotionLinstener | MouseEvent | mouseDragged(MouseEvent)
mouseMoved(MouseEvent) |
MouseMotionAdapter |
TextListener | TextEvent | textValueChanged(TextEvent) | ~ |
WindowListener | WindowEvent | windowActivated(WindowEvent)
windowClosed(WindowEvent) windowClosing(WindowEvent) windowDeactivated(WindowEvent) windowDeiconified(WindowEvent) windowIconified(WindowEvent) windowOpened(WindowEvent) |
WindowAdapter |
Table Notes:
1) Note Event classes are
provided as arguments to the methods. i.e. actionPerformed(ActionEvent
ae)
2) Adapter classes are provided
for any listener interfaces defining more than one method
3) All these event classes
and interfaces are made accessible with
import java.awt.event.*;
4) These classic AWT event
types are compatible with swing components, which add many new
event
types, i.e. HyperLinkEvent, most which are associated with MVC architecture.
To see a list you
can go
to http://developer.java.sun.com/developer/onlineTraining/GUI/Swing2/shortcourse.html
Unlike the AWT event listener classes, there are few adapter classes
for the swing event
interfaces at this time. If you have an interest in only one of the
event sub-types, you have to
implement all the methods of the interface.
The hierarchy of ActionEvent in the diagram below shows ActionEvent
derives from
AWTEvent and EventObject. The EventObject
class
provides the important method
getSource( ) whichreturns
the object that originated the event. AWTEvent
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 occured. For instance a mouse event
contains several (seven) possible actions, a click, a drag etc. A click
is represented
by the int stored in, MouseEvent.MOUSE_CLICKED.
Class ActionEvent //abreviated from the jdk1.2.2 API java.lang.Object | +--java.util.EventObject | +--java.awt.AWTEvent | +--java.awt.event.ActionEvent public class ActionEvent extends AWTEvent A semantic event which indicates that a component-defined
action occured. This high-level
The object that implements the ActionListener interface
gets this ActionEvent when the
Field Summary
Constructor Summary
Method Summary
|
Differentiating the event source when the sources use the same listener
In the event that a number of button use the container as the listener
via the this keyword,
determining which button was activated can be sorted in a if statement
using the method
getSource( ), which returns the
reference to the event source. getSource( ) is
defined in
java.util.EventObject, the root
event class from which the other event classes extend.
You may also use the string associated with a component for identification
using the
ActionEvent method, getActionCommand( ). The
following two examples show both
methods in action.
Example 1
public void actionPerformed(ActionEvent
ae){
Object source=ae.getSource( );
// using getSource() to differentiate source
if (source.equals(jb1)){
j1Text.setText("A character");
}
else if (source.equals(jb2))
j2Text.setText("Another character");
// etc.
}
}
Example 2
// use String class' trim() method to get rid of leading and trailing spaces
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.
}
}
Notice MouseEvent is derived from a hierarchy two generations deeper
so inherits more
specialized behaviour than ActionEvent
Class MouseEvent //abreviated from the jdk1.2.2 API java.lang.Object | +--java.util.EventObject | +--java.awt.AWTEvent | +--java.awt.event.ComponentEvent | +--java.awt.event.InputEvent | +--java.awt.event.MouseEvent public class MouseEvent extends InputEvent An event which indicates that a mouse action occurred
in a component. This event is used
A MouseEvent object is passed to every MouseListener
or MouseAdapter object which
A MouseEvent object is also passed to every MouseMotionListener
or
Field Summary
Constructor Summary
Method Summary
|
Steps in adding an event listener to a component
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) call addActionListener( ) on*the
component passing in the listener
class object as the argument.
*Note: 'on' in this context is 'programmer dialect' meaning 'belonging to' or 'a method of'
Five variations of adding listeners
to components
1) An external class listens for a component events
// 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 constuction
of the GUI won't have references to the components inside the GUI.
One way to remove
this limitation is to define the listener with a constructor that takes
as arguments the
components you wish to make changes to when actions occur.
// inside a class extending JFrame or JApplet
Example
// Code showing an externally
defined listener defined with a constructor that
// allows GUI components to
be passed into it and thereby allowing it to be tied
// in to the object members
defined by the constructor.
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();
}
}
2) The containing class instance listens for events
Making the containing class the listener is very popular and common.
It has
the advantage of being simple to implement. The disadvantage comes
if there
are two many components using this to process their commands. Even
still
it is a nice way to handle events and we add a complete example for
your
reference.
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
class Crate extends JFrame implements ActionListener{ JButton one,two,three,exit; Crate( ){
one.addActionListener(this);
getContentPane( ).add(one);
public void actionPerformed (ActionEvent
ae){
|
3) The component is subclassed to listen to itself
// again
this used in a subclass of the component
// here, the component
is subclassed, the parent constructor is invoked via super
from the
// child constructor,
and the component itself is referenced via this
class
SelfAuditButton extends Button implements ActionListener{
public SelfAuditButton(String label){
super(label);
addActionListener(this);
}
//next the required, implementation of the interfaces method
public
void actionPerformed(ActionEvent ae){
System.out.println("action performed by a self listener");
}
}
4. An anonymous inner class listens for events
// This is often seen in Frame and JFrame subclasses to close the window
// assume frame is a reference to the enclosing frame instantiation
frame.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.
The
anonymous inner class a
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.
// Supplemental: our experience showed this
worked on AWT components but not swing
5. bypass listening and enable the component to process its own events
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.
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 class
EnabledButton extends Button{
public EnabledButton(String label){
super(label);
enableEvents(AWTEvent.ACTION_EVENT_MASK);
}
public void processActionEvent(ActionEvent
ae){
System.out.println("Enabled Button does it's own action");
super.processActionEvent(ActionEvent ae); //
call to super for button's action listeners
}
}