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 architecture, 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.
XXXListener //
for example ItemListener
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.
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.
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
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
|
most
apps
wouldn't
use
this |
ComponentListener
|
accepts component events. |
modifying
a
component'
size,
location
or visibility |
ContainerListener |
accepts container events. |
adding
or
removing
a |
FocusListener |
accepts
keyboard
focus |
tabbing
or
requesting
focus |
ItemListener |
accepts item events. |
An
item
selected
from
a
list or |
KeyListener |
accepts keyboard events |
Keyboard created KeyEvents |
MouseListener |
accepts
mouse
events
(press,
release, click, enter and exit) |
The
mouse
creates |
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.)
Listener Interface |
Interface methods |
Adapter class |
ActionListener |
actionPerformed (ActionEvent) |
~ |
AdjustmentListener |
adjustmentValueChanged |
~ |
ComponentListener |
componentHidden(ComponentEvent) |
ComponentAdapter |
ContainerListener |
componentAdded(ContainerEvent) |
ContainerAdapter |
FocusListener |
focusGained(FocusEvent) |
FocusAdapter |
ItemListener |
itemStatedChanged(ItemEvent) |
~ |
KeyListener |
keyPressed(KeyEvent) |
KeyAdapter |
MouseListener |
mouseClicked(MouseEvent) |
MouseAdapter |
MouseMotionLinstener |
mouseDragged(MouseEvent) |
MouseMotionAdapter |
TextListener |
textValueChanged(TextEvent) |
~ |
WindowListener |
windowActivated(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
Extending Window Adapter
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 Classes |
|
ActionEvent |
A semantic event indicating a
component-defined action |
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 |
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 |
InputEvent |
The root event class for all component-level input events. |
InputMethodEvent |
Input method events contain information
about text that is |
InvocationEvent |
An event which executes the run( ) method
on a Runnable |
ItemEvent |
A semantic event which indicates that an
item was |
KeyEvent |
An event which indicates that a keystroke occurred in a component. |
MouseEvent |
An event which indicates that a mouse
action occurred |
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 |
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
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 |
Event
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 |
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, |
Constructs an ActionEvent object. |
ActionEvent(Object source, int id,
|
Constructs an ActionEvent |
ActionEvent Method
Summary
String |
Returns the command string associated |
int getModifiers( ) |
Returns the modifier keys held down during |
String |
Returns a parameter string identifying this |
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 |
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 |
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 |
Translates the event's coordinates to a new position by adding specified offsets. |
Example of int Values Returned with Mouse Events & getX( ), getY( )
Methods
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.*;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, |
public void |