lecture13intro_Events

Download Report

Transcript lecture13intro_Events

Events
Here, we review event handling one more time.
To understand how events work in Java, we have to
look closely at how we use GUIs.
When you interact with a GUI, there are many events
taking place each second. Only a few of these,
however, may actually be ‘delivered’ to the
application.
Events
Java uses a “delegation” event model found in many
other toolkits.
Under the delegation model, components fire events,
which can be caught and acted on by listeners. A
listener is linked to a component through a registration
process.
The delegation event model is contrasted to an event
filtration model where all events are delivered to target
components regardless of whether they asked for them.
General Overview
Recall our first
consideration of
events, where our first
frame would not close,
even when the end of
main() was reached.
We explained this behavior by thinking of our program as
entering an “infinite loop” when the graphics are shown.
This ‘infinite loop’ is actually an event-driven cycle, but
we can think of it as a “while (true)” structure that
periodically polls for user input.
The Real Story
import java.awt.*;
public class HelloGUI {
public static void main (String[ ] arg) {
System.out.println
(“About to make GUI”);
Frame f = new Frame (“Hello GUIs”);
f.setSize( 200, 200 );
f.show();
System.out.println
(“Finished making GUI”);
}// main
}// class HelloGUI
We usually think of our program as a single,
linear set of steps being executed. But
something special happens when we create
graphical objects.
The Real Story
When Java sees that you’ve created a GUI, your program gets a
second “set” of linear instructions.
import java.awt.*;
public class HelloGUI {
public static void main (String[ ] arg) {
System.out.println
(“About to make GUI”);
Frame f = new Frame (“Hello GUIs”);
f.setSize( 200, 200 );
f.show();
System.out.println
(“Finished making GUI”);
}// main
}// class HelloGUI
This is actually a
separate “thread”, but
don’t worry if that’s
unclear for now. We
can think of this as a
second part of our
program than handles
special graphicsrelated tasks (such as
drawing the window,
etc.)
Graphics Thread
import java.awt.*;
public class HelloGUI {
public static void main (String[ ]
arg) {
System.out.println
(“About to make GUI”);
Frame f = new Frame (“Hello
GUIs”);
f.setSize( 200, 200 );
f.show();
System.out.println
(“Finished making GUI”);
}// main
}// class HelloGUI
Both of these “threads” are
your program. You coded one
of the lines of control. Java
provides the other one. That
way, things appear to happen
simultaneously--your code
executes and the window gets
redrawn, refreshed, etc.
Java quickly switches between your code and the
graphics drawing code, so that both threads appear
to execute at the same time.
Don’t Panic
Don’t worry if this “thread” stuff is confusing. Other
classes go into this in detail. For our purposes, we only
have to understand that there are two areas of a graphic
program.
1
2
The code we
wrote in main()
and other methods
The code Java
provides to handle the
graphics side of
things.
import java.awt.*;
public class HelloGUI {
public static void main (String[ ] arg) {
System.out.println
(“About to make GUI”);
Frame f = new Frame (“Hello GUIs”);
f.setSize( 200, 200 );
f.show();
System.out.println
(“Finished making GUI”);
}// main
}// class HelloGUI
Your Code
Graphics
Who Cares?
This model is very important to understand because
as it turns out, when an event occurs--such as mouse
click, it happens in the “graphics side” of the model.
import java.awt.*;
public class HelloGUI {
public static void main (String[ ] arg) {
System.out.println
(“About to make GUI”);
Frame f = new Frame (“Hello GUIs”);
f.setSize( 200, 200 );
f.show();
System.out.println
(“Finished making GUI”);
}// main
}// class HelloGUI
Mouse Click
occurs
The code trapping
this event appears
in the graphics thread
Actually, there’s a separate “event queue” that handles incoming events. But this is
already complicated enough. Let’s just generalize and imagine that all events arrive in the
‘graphics side’ of things.
“Call backs”
Since the event arrived in the ‘graphics half’ of our
program, we need a way to have it call a method in our
program. This is known as a “call back”.
Our event
handling
code
import java.awt.*;
public class HelloGUI {
public static void main (String[ ] arg) {
System.out.println
(“About to make GUI”);
Frame f = new Frame (“Hello GUIs”);
f.setSize( 200, 200 );
f.show();
System.out.println
(“Finished making GUI”);
}// main
}// class HelloGUI
callback
The code trapping
this event appears
in the graphics thread
How?
So Java needs to call some event handling code that we
write. The trouble is, how will Java know what we called
out method? We can name them anything we want, and
Java won’t necessarily know what methods handle
events.
import java.awt.*;
public class HelloGUI {
public static void main (String[ ] arg) {
System.out.println
(“About to make GUI”);
Frame f = new Frame (“Hello GUIs”);
f.setSize( 200, 200 );
f.show();
System.out.println
(“Finished making GUI”);
}// main
}// class HelloGUI
callback
But Wait!
We can use
interfaces, right?
Event Interfaces
Java uses interfaces as its primary event handling
scheme. If you implement an event-related interface,
Java will know which methods to call. This is because
the contract nature of interfaces requires all methods to
appear in the implementing class.
ActionListener
import java.awt.*;
public class HelloGUI {
public static void main (String[ ] arg) {
System.out.println
(“About to make GUI”);
Frame f = new Frame (“Hello GUIs”);
f.setSize( 200, 200 );
f.show();
System.out.println
(“Finished making GUI”);
}// main
}// class HelloGUI
public void actionPerformed
(ActionEvent e) {
// code doing something
}
This method MUST
be there, so Java knows
it can “callback” to it
callback
Why “Delegation”?
Since any class can implement any interface, we can
have just about any object handle the events. We can
therefore “delegate” event handling to this object.
Remember MVC?
M
V
C
Some (smart) folks
believe you should
organize where the
events get handled.
(This is the “controller”
aspect to MVC.)
Why “Registration”?
We are told that “event registration” must occur before event
handling will occur. What does this mean?
Well, since we can have any class handle events, we need to tell
Java which object implements the proper event handling interface.
This “registers” the component as being interested in receiving
callbacks.
import java.awt.*;
public class HelloGUI {
public static void main (String[ ] arg) {
System.out.println
(“About to make GUI”);
Frame f = new Frame (“Hello GUIs”);
f.setSize( 200, 200 );
f.show();
System.out.println
(“Finished making GUI”);
}// main
}// class HelloGUI
Where to
callback?
Another example
public class DemoFrame extends Frame {
public DemoFrame( ) {
super (“A poor use of inheritance, but simple”);
Handler2 h = new Handler2();
this.setSize(400,400);
this.setLayout(new FlowLayout());
Button b = new Button (“Click me”);
this.add(b);
this.show();
} // Constructor
public static void main(String args[]) {
DemoFrame df;
df = new DemoFrame();
} // main
} // DemoFrame
Another example
public class Handler2 implements ActionListener {
public void actionPerformed(ActionEvent e) {
System.out.println (“Button was clicked”);
}
} // Handler2
Why doesn’t this work?
Another example
public class DemoFrame extends Frame {
public DemoFrame( ) {
super (“A poor use of inheritance, but simple”);
Handler2 h = new Handler2();
this.setSize(400,400);
this.setLayout(new FlowLayout());
Button b = new Button (“Click me”);
b.addActionListener(h);
this.add(b);
this.show();
} // Constructor
public static void main(String args[]) {
DemoFrame df;
df = new DemoFrame();
} // main
} // DemoFrame
Question...
We said we had to have a Listener to handle the
event and it had to be an object. Does it have to be
a separate object?
Another example
public class DemoFrame extends Frame implements ActionListener {
public DemoFrame( ) {
super (“A poor use of inheritance, but simple”);
Handler2 h = new Handler2();
this.setSize(400,400);
this.setLayout(new FlowLayout());
Button b = new Button (“Click me”);
b.addActionListener(this);
this.add(b);
this.show();
} // Constructor
public void actionPerformed(ActionEvent e) {
System.out.println (“Button was clicked”);
}
public static void main(String args[]) {
DemoFrame df;
df = new DemoFrame();
} // main
} // DemoFrame
Questions?
BSOD
This program has performed
an illegal instruction and will
be shutdown. Please shell out another
$200 for a more stable version
of this OS.
Just Kidding
Anything can be an event. Including general protection
faults.
But for the most part, good programming dictates that
handled events should come from the following area of
input:
a Mouse events
b
Keyboard events
c
Timing events
d
Other user action inputs
Java Event Handling Strategies
With this basic understanding, we can investigate the
FOUR primary means of event handling in Java
1
Event Listeners
2
Event Adapters
Very
general
3
Semantic Events
Very
old
4
Inheritance-based event handling
Very
similar
You are 100% guaranteed to have a quiz question on this
Listeners
From the discussion about callbacks, we noted
that interfaces were the primary mechanism for
structuring our event handling.
There are numerous event interfaces we can
implement, roughly divided around categories of
events.
The next slide lists many of them. Don’t freak
out because there are so many.
We’ll highlight the most commonly used ones. . .
Yikes. So Many Choices
Package java.awt.event features:
Most commonly
used
ActionListener
MouseListener
MouseMotionListener
AdjustmentListener
ComponentListener
FocusListener
ContainerListener
ItemListener
KeyListener
WindowListener
TextListener
As it turns out, the ActionListener
is part of the “semantic” event
group, even though it’s an
interface. So let’s focus on simple
events like MouseListener...
MouseListener
The MouseListener interface has several methods we have to code:
public void mouseClicked(MouseEvent e) { }
-- a timing-based determination; else
the events are processed as
pressed/releases
public void mouseEntered(MouseEvent e) { }
-- entry into component
public void mouseExited(MouseEvent e) { }
-- exit from component
public void mousePressed(MouseEvent e)
-- simply a press . . .
{ }
public void mouseReleased(MouseEvent e){ }
-- ... the corresponding release
import java.awt.*;
import java.awt.event.*;
public class MouseFrame implements MouseListener{
Color highlight, normal;
boolean bHighlight = true;
Frame fr;
public MouseFrame () {
fr = new Frame(“For demonstration only”);
highlight = Color.red;
normal = Color.gray;
To keep it simple,
frame.setSize(400,400);
Button b = new Button("Click");
we ignore
b.addMouseListener(this);
WindowEvents
fr.setBackground(normal);
fr.setLayout(new FlowLayout());
fr.add(b);
fr.show();
}
public static void main(String[] args) {
new MouseFrame();
}
(more)
Note that when
we run this the
constructor will
run and terminate
public void mouseReleased(MouseEvent e){
System.out.println ("Changing color");
if (bHighlight)
frame.setBackground(highlight);
else
frame.setBackground(normal);
bHighlight = !bHighlight;
}
public
public
public
public
void
void
void
void
mouseClicked(MouseEvent e) {}
mouseEntered(MouseEvent e) {}
mouseExited(MouseEvent e) {}
mousePressed(MouseEvent e) {}
} // MouseFrame
Event Listener Summary
We need a class that implements the appropriate
listener type.
We need to “register” a component as interested in
receiving events:
addXYZListener ( <listener instance> );
Whatever listener we’re working with. E.g.:
addMouseListener(this);
addMouseMotionListener(myEventHandler);
Observations
1
The “WindowListener” interface required numerous
methods.
2
But only one was important to us.
3
All the rest were coded as “no-op” or no operation
methods.
There’s another strategy using “adapters”, using
inheritance that could have saved us some trouble...
Adapters
Java has built-in classes called “event
adapters” that implement each of the
various event listeners.
But all of these methods are “no-ops”.
public class MouseAdapter implements MouseListener {
public void mouseClicked(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
}
WHY?
Key to Adapters: Inheritance
MouseAdapter
MouseFrame
Why a bunch of no-op methods?
Well, if you subclass the adapter, your class IS-A type
of event listener.
And you then only have to override the one or two
methods you care about. The rest can be inherited as
“no-ops”
import java.awt.*;
import java.awt.event.*;
public class MouseFrame extends MouseAdapter
implements MouseListener{
Color highlight, normal;
boolean bHighlight = true;
Frame frame;
public MouseFrame () {
frame = new Frame(“For demonstration only”);
highlight = Color.red;
normal = Color.gray;
frame.setSize(400,400);
Button b = new Button("Click");
b.addMouseListener(this);
frame.setBackground(normal);
frame.setLayout(new FlowLayout());
frame.add(b);
frame.show();
}
Parent
public void mouseClicked(MouseEvent e) {}
class
public void mouseEntered(MouseEvent e) {}
takes
public void mouseExited(MouseEvent e) {}
care of
public void mousePressed(MouseEvent e) {}
these
Example (cont’d)
public void mouseReleased(MouseEvent e){
System.out.println ("Changing color");
if (bHighlight)
frame.setBackground(highlight);
else
frame.setBackground(normal);
bHighlight = !bHighlight;
}
We override
the one or
two methods
we care about
public static void main(String[] args) {
new MouseFrame();
}
} // MouseFrame
Same behavior; less code;
but we use up our
single inheritance
public class MouseAdapter implements MouseListener {
public void mouseClicked(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
}
import java.awt.*;
import java.awt.event.*;
public class MouseFrame extends MouseAdapter {
Color highlight, normal;
boolean bHighlight = true;
Frame frame;
public MouseFrame () {
frame = new Frame(“For demonstration only”);
highlight = Color.red;
normal = Color.gray;
frame.setSize(400,400);
Button b = new Button("Click");
b.addMouseListener(this);
frame.setBackground(normal);
frame.setLayout(new FlowLayout());
frame.add(b);
frame.show();
}
public void mouseReleased(MouseEvent e) {
System.out.println ("Changing color");
if (bHighlight)
frame.setBackground(highlight);
else
frame.setBackground(normal);
bHighlight = !bHighlight;
}
public static void main(String[] args) {
new MouseFrame();
}
} // MouseFrame
This comes with Java!
Big Picture Time
So far, we’ve tinkered(kurcalamak)
with different ways of coding
very low-level event handling.
But what if our event handling needs are very general.
Consider this simple dialog box:
Are you sure you wish
to proceed ?
cancel
ok
There’s not much interaction
that needs to be supported.
Mouse entry/exit might not
be needed at all.
Semantic Events
Wouldn’t it be convenient to abstract all of these small
events into one “just-tell-me-when-its-clicked” event?
public
public
public
public
public
void
void
void
void
void
mouseClicked(MouseEvent e) {}
mouseEntered(MouseEvent e) {}
mouseExited(MouseEvent e) {}
mousePressed(MouseEvent e) {}
mouseReleased(MouseEvent e) {}
M1A1 Abstractor
public void actionPerformed(ActionEvent e)
Semantic Events
Semantic events provide a means of handling
events at the component level. That is, you will
not address fine-grained events like mouse entry and
exit. Instead, you’ll only receive a callback when the
component has received some type of input event
Semantic Events
Semantic Event
ActionEvent
Components and Firing Event
Button (activated)
List (double-clicked)
MenuItem (selected)
TextField (typed)
There are numerous
event handlers for
low-level events
associated
with these widgets.
AdjustmentEvent
Scrollbar (moved)
ItemEvent
Checkbox (toggled)
CheckboxMenuItem (selected)
Choice (selected)
List (selected)
TextEvent
TextComponent (text changes)
Note: ALL input is sent into one of these FOUR categories.
Example
import java.awt.*;
import java.awt.event.*;
public class MouseFrame extends Frame
implements ActionListener {
Color highlight, normal;
boolean bHighlight = true;
public MouseFrame () {
highlight = Color.red;
normal = Color.gray;
this.setSize(400,400);
Button b = new Button("Click");
b.addActionListener(this);
this.setBackground(normal);
this.setLayout(new FlowLayout());
this.add(b);
this.show();
}
Example (cont’d)
public void actionPerformed(ActionEvent e){
System.out.println ("Changing color");
if (bHighlight)
this.setBackground(highlight);
else
this.setBackground(normal);
bHighlight = !bHighlight;
}
public static void main(String[] args) {
new MouseFrame();
}
} // MouseFrame
We therefore lose the ability to handle very finegrained events (e.g., mouse entry/exit). But that
might be acceptable for certain applications.
(non) Option #4: JDK 1.02 Events
• An earlier version of Java used “boolean” return values
to indicate consumption of events. Events were delivered to
components whether or not they registered for events.
• Not recommended; still used for some web development
• Do not mix JDK 1.1 and JDK 1.02 event handlers--the
component ceases to function!
• Rare use: JDK 1.02 guarantees which event will arrive
first to a component.
• More common use: some browsers only support JDK 1.02--a
very early version of Java that uses this model. Professional
applet developers still use this technique. Many browsers are
now supporting the JDK 1.1 event model.
Event Handling Options: How to Decide
Costs
Event Listeners
(interfaces)
Must code all
methods; wasteful
no-ops result
Benefits
Keep all
events in
single class
Event Adapters
(inheritance)
Uses up single
inheritance
opportunity
Good abstraction;
override those
methods
you need
Semantic Events
Simplifies
event handling
Loss of
granular
control;
linear code
Debugging re: Event Handlers
• Debugging an event-driven program (whether applet or graphical
application) is more tricky than debugging a non-event-driven
program.
• With an event-driven Java program, you don't explicitly code any
kind of event-handling loop that "polls" for occurring events, then
calls the appropriate handler(s) for those events.
• Instead, the Java internals handle this polling action for you.
Debugging becomes trickier because now you have to make sure
that your event handling code works correctly.
• You also have to make sure you're handling the correct events in
the first place! For example, your code for mouseEntered( ) may
work perfectly, but if you're expecting it to get called when the
user clicks a mouse button, it won't be!
Debugging re: Event Handlers
So, in debugging event-driven programs written
with Java, the steps are:
• Be sure you're handling the appropriate events:
Map out on paper what events get thrown from what
components, and what class(es) handle them.
• Handle the events appropriately:
This is the kind of debugging you're already familiar with:
Once you're sure the appropriate events are getting
handled, the rest is being sure the event-handling
code (and the code that the event handlers call) work.
Events: A Short Example
To compare the three event handling techniques, let’s see a *brief*
example how all three might work on a common problem.
Goal: Create a
simple Frame that
holds a TextArea
and Button.
TEXT AREA
The Button toggles
the ability to edit
the TextArea
BUTTON
Panel subclass
My Program
The Panel
holding the
Button and
TextArea is
placed in a
Frame
subclass, which
handles its own
disposal
import java.awt.*;
import java.awt.event.*;
public class MyFrame extends Frame implements WindowListener{
public static final int iWidth = 300, iHeight = 500;
public MyFrame() {
this.setSize(iWidth, iHeight);
this.addWindowListener(this);
Constructor
BorderLayout border = new BorderLayout();
this.setLayout(border);
}
public void windowClosing (WindowEvent e) {
e.getWindow().setVisible(false);
e.getWindow().dispose();
System.exit(0);
}
public void windowActivated(WindowEvent e) {}
WindowListener
public void windowClosed(WindowEvent e) {}
public void windowDeactivated(WindowEvent e) {}
public void windowDeiconified(WindowEvent e) {}
Frames are not
public void windowIconified(WindowEvent e) {}
self-disposing!
public void windowOpened(WindowEvent e) {}
(Setting Frame
invisible first
}// class MyFrame
eliminate flicker.)
import java.awt.*;
import java.awt.event.*;
public class MyFrame extends Frame {
“Anonymous
public static final int
Inner Class”:
iWidth = 300,
used as a short
iHeight = 500;
public MyFrame()
cut. For your
{
code, use listeners
this.setSize(iWidth, iHeight);
this.addWindowListener
(new WindowAdapter()
{
Frames are not
public void windowClosing (WindowEvent e)
{
self-disposing!
e.getWindow().setVisible(false);
(Setting Frame
e.getWindow().dispose();
invisible first
System.exit(0);
eliminate flicker.)
}
});
BorderLayout border = new BorderLayout();
this.setLayout(border);
}
}// class MyFrame
import java.awt.*;
public class Driver
{
public static void main (String arg[]){
Notepad note = new Notepad();
MyFrame f = new MyFrame();
f.add(note, BorderLayout.CENTER);
f.show();
}//main
}//class Driver
A simple driver. Notice that so far, we’ve abstracted
the Frame subclass into something very
generic and reusable--IT’S NOT JUST TIED
TO THIS PROGRAM!
Variation #1: Listener Events
(MouseListener)
import java.awt.*;
import java.awt.event.*;
class Notepad extends Panel implements MouseListener
{
Button toggle;
The Driver and MyFrame classes were
TextArea scratch;
generic enough to work with any
boolean bWritable;
version of this example. Here, however,
public Notepad()
we need to create a specific event handler.
{
super("Wasted inheritance");
this.setLayout (new BorderLayout());
scratch = new TextArea(20,20);
Panel buttonPanel = new Panel();
toggle = new Button ("Freeze/Unfreeze");
buttonPanel.add(toggle);
add(scratch, BorderLayout.CENTER);
add(buttonPanel, BorderLayout.SOUTH);
toggle.addMouseListener(this);
bWritable = false;
}// constructor
/* . . . Continued from “class Notepad extends Panel
implements MouseListener” . . . */
public void setWritable(boolean bWritable){
this.bWritable = bWritable;
}//setWritable
public boolean getWritable() {
return bWritable;
}//getWritable
Implement the
method one needs;
the rest are “no-ops”
public TextArea getTextArea(){
return scratch;
}//getTextArea
public void mousePressed(MouseEvent e) {
getTextArea().setEnabled(getWritable());
setWritable(!getWritable());
}//mousePressed
public void mouseReleased(MouseEvent e) {;}
public void mouseClicked(MouseEvent e) {;}
public void mouseEntered(MouseEvent e) {;}
public void mouseExited(MouseEvent e) {;}
}//class Notepad
Driver
main
Notepad note
MyFrame f
Notepad extends Panel
Button toggle
TextArea scratch
boolean bWritable
My Program
TEXT AREA
BUTTON
Variation #2: Adapter Events
(MouseAdapter)
import java.awt.*;
import java.awt.event.*;
class Notepad extends Panel { /* NOTE: NO INTERFACE! */
Button toggle;
TextArea scratch;
boolean bWritable;
public void setWritable(boolean bWritable){
this.bWritable = bWritable;
}//setWritable
public boolean getWritable(){
return bWritable;
}//getWritable
public TextArea getTextArea(){
return scratch;
}//getTextArea
/* . . . Continued from “class Notepad extends Panel” */
public Notepad(){
super();
this.setLayout (new BorderLayout());
scratch = new TextArea(20,20);
Panel buttonPanel = new Panel();
toggle = new Button ("Freeze/Unfreeze");
buttonPanel.add(toggle);
add(scratch, BorderLayout.CENTER);
add(buttonPanel, BorderLayout.SOUTH);
Note use
of anonymous
inner class.
toggle.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e)
{
getTextArea().setEnabled(getWritable());
setWritable(!getWritable());
}
});/* end of anonymous inner class */
bWritable = false;
}// constructor
Variation #3: Another Way!
import java.awt.*;
import java.awt.event.*;
public class AnotherHandler extends MouseAdapter {
Notepad np;
public AnotherHandler(Notepad np) {
this.np = np;
} // Constructor
public void mousePressed(MouseEvent e)
{
np.getTextArea().setEnabled(np.getWritable());
np.setWritable(!np.getWritable());
}
} // AnotherHandler
Variation #3: Another Way
import java.awt.*;
import java.awt.event.*;
class Notepad extends Panel { /* NOTE: NO INTERFACE! */
Button toggle;
TextArea scratch;
boolean bWritable;
public void setWritable(boolean bWritable){
this.bWritable = bWritable;
}//setWritable
public boolean getWritable(){
return bWritable;
}//getWritable
public TextArea getTextArea(){
return scratch;
}//getTextArea
/* . . . Continued from "class Notepad extends Panel" */
public Notepad(){
super();
this.setLayout (new BorderLayout());
scratch = new TextArea(20,20);
Panel buttonPanel = new Panel();
toggle = new Button ("Freeze/Unfreeze");
buttonPanel.add(toggle);
add(scratch, BorderLayout.CENTER);
add(buttonPanel, BorderLayout.SOUTH);
AnotherHandler ah = new AnotherHandler(this);
toggle.addMouseListener(ah);
bWritable = false;
}// constructor
Variation #4: Semantic Events
(ActionListener)
import java.awt.*;
import java.awt.event.*;
class Notepad extends Panel implements ActionListener {
Button toggle;
TextArea scratch;
boolean bWritable;
public Notepad(){
super();
this.setLayout (new BorderLayout());
scratch = new TextArea(20,20);
Panel buttonPanel = new Panel();
toggle = new Button ("Freeze/Unfreeze");
buttonPanel.add(toggle);
add(scratch, BorderLayout.CENTER);
add(buttonPanel, BorderLayout.SOUTH);
toggle.addActionListener(this);
bWritable = false;
}// constructor
/* . . . Continued from "class Notepad extends Panel
implements ActionListener" . . . */
public void setWritable(boolean bWritable){
this.bWritable = bWritable;
}//setWritable
public boolean getWritable(){
return bWritable;
}//getWritable
public TextArea getTextArea() {
return scratch;
}//getTextArea
public void actionPerformed (ActionEvent e) {
getTextArea().setEnabled(getWritable());
setWritable(!getWritable());
}//actionPerformed
}//class Notepad
Event Handlers: Final Review
This simple example shows that sometimes, semantic event handlers
perform the task perfectly.
In the drawing applet example, the semantic event handler was unable
to offer help. In this example, it works perfectly, and was easier to
follow and implement.
Note that a few of the examples in this notepad demonstration used
“anonymous inner classes”. You will not be required to use
anonymous inner classes in this course; however, they are used a lot
and if you have never seen them before they can be startling...be
prepared.
Cross Class Communication
Working with events often requires us to have
“upstream” references, so that event handlers can call
methods in the classes that created them.
Another (Familiar?) Example
To illustrate cross-class
communication,let’s make a
simple program that’s similar
the examples used in
previous slides.
We’ll use a Frame and a class
to handle events.
When the mouse enters a
button, the button will flash,
and will update the Frame’s
title.
The Madness HAS-A Method
FlashDemo
(a JFrame)
EventHandler
(a MouseListener)
Makes an array of
JButtons...
Saves the frame and
button reference . . .
... sets their event
handler, passing
in “this” and
the button.
... so it can call back to
the frame to set
its title, and change
the button
The two classes have to talk to each other, and
therefore need references to each other.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class FlashDemo extends JFrame implements WindowListener {
JButton[][] buttons;
Key Method
public FlashDemo () {
this.addWindowListener(this);
Call
buttons = new JButton[4][4];
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(4,4,10, 10));
for (int i=0; i < buttons.length; i++)
for (int j=0; j < buttons[i].length; j++){
buttons[i][j] = new JButton
("[" + i +"][" + j +"]");
EventHandler eh = new EventHandler
(this, buttons[i][j]);
buttons[i][j].addMouseListener(eh);
panel.add(buttons[i][j]);
}
this.getContentPane().add(panel);
this.setSize(350,350);
}
/* class FlashDemo (cont’d) */
public void windowClosing(WindowEvent e) {
System.exit(0);
}
public void windowActivated(WindowEvent e) {}
public void windowClosed(WindowEvent e) {}
public void windowDeactivated(WindowEvent e) {}
public void windowDeiconified(WindowEvent e) {}
public void windowIconified(WindowEvent e) {}
public void windowOpened(WindowEvent e) {}
public static void main (String[] arg){
new FlashDemo().show();
}
} // FlashDemo
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
public class EventHandler implements MouseListener {
FlashDemo theFrame;
JButton button;
Color highlight;
Color original;
public EventHandler (FlashDemo theFrame, JButton button) {
this.theFrame = theFrame;
this.button = button;
highlight = Color.yellow;
original = button.getBackground();
}
We SAVE reference to the frame that made
this class, and the button it has to control
/* class EventHandler (cont’d)
*/
public void mouseClicked(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {
theFrame.setTitle
("You are now in Button #" + button.getLabel());
button.setBackground(highlight);
}
public void mouseExited(MouseEvent e) {
theFrame.setTitle("");
button.setBackground(original);
}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
} // EventHandler
Additional Presentation...
Questions?