Events Here, we review event handling one more time. To understand how events work in Java, we have...
-
Upload
marjory-gregory -
Category
Documents
-
view
213 -
download
0
Transcript of Events Here, we review event handling one more time. To understand how events work in Java, we have...
EventsEvents
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.
EventsEvents
Java uses a “delegation” event model found in many other toolkits.
Under the delegation model, componentscomponents fire eventsevents, which can be caught and acted on by listenerslisteners. A listener is linked to a component through a registrationregistration process.
The delegation eventdelegation event model is contrasted to an event event filtration model filtration model where all events are delivered to target components regardless of whether they asked for them.
General OverviewGeneral Overview
ExplanationExplanationWhen the Java VM createdour Frame, it entered into akind of ‘infinite loop’,waiting for input andevents. (This is commonof graphical toolkits.)
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
while(true){ //get user input // handle event}
Since we didn’twrite any eventhandlers, not eventhe “windowdisposal” x works.
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 StoryThe 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 StoryThe 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
When Java sees that you’ve created a GUI, your program gets a second “set” of linear instructions.
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 graphics-related tasks (such as drawing the window, etc.)
Graphics ThreadGraphics Threadimport 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.
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
Don’t PanicDon’t PanicDon’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 The code weThe code wewrote in main()wrote in main()and other methodsand other methods
2The code Java The code Java provides to handle the provides to handle the graphics side of graphics side of things.things.
GraphicsGraphicsYour CodeYour Code
Who Cares?Who Cares?
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 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.
Mouse Clickoccurs
The code trappingthis 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”Call backs”
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
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”.
callbackcallback
Our eventhandling
code
The code trappingthis event appears
in the graphics thread
How?How?
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
callbackcallback
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.
But Wait!But Wait!
We can useWe can useinterfaces, right?interfaces, right?
Event InterfacesEvent InterfacesJava 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.
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
callbackcallbackpublic void actionPerformed (ActionEvent e) { // code doing something }
This method This method MUSTMUSTbe there, so Java knowsbe there, so Java knowsit can “callback” to itit can “callback” to it
ActionListener
Why “Delegation”?Why “Delegation”?
Since any class can implement any interface, we can have just about any object handle the events. We can therefore “delegate”“delegate” event handling to this object.
Remember MVC?
Some (smart) folks believe you should organize where theevents get handled.
(This is the “controller” aspect to MVC.)
MM
CC
VV
Why “Registration”?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 toWhere tocallback?callback?
Another exampleAnother examplepublic 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 exampleAnother example
public class Handler2 implements ActionListener {
public void actionPerformed(ActionEvent e) {
System.out.println (“Button was clicked”);
}
} // Handler2
Why doesn’t this work?Why doesn’t this work?
Another exampleAnother examplepublic 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...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 exampleAnother examplepublic 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?Questions?
This program has performed an illegal instruction and will
be shutdown. Please shell out another$200 for a more stable version
of this OS.
BSOD
Just KiddingJust KiddingAnything 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:
Keyboard events
Timing events
Mouse events
Other user action inputs
a
b
c
d
Java Event Handling StrategiesJava Event Handling Strategies
With this basic understanding, we can investigate theFOURFOUR primary means of event handling in Java
Event Adapters
Semantic Events
Event Listeners
Inheritance-based event handling
1
2
3
4
Very similar
Verygeneral
Very old
You are 100% guaranteed to have a quiz question on thisYou are 100% guaranteed to have a quiz question on this
ListenersListenersStrategy
StrategyNo. 1No. 1
From the discussion about callbacks, we notedthat 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. . .
Most commonlyused
Yikes. So Many ChoicesYikes. So Many Choices
Package java.awt.event features:
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...
MouseListenerMouseListenerThe MouseListener interface has several methods we have to code:
public void mouseClicked(MouseEvent e) { }public void mouseClicked(MouseEvent e) { }-- a timing-based determination; else-- a timing-based determination; else
the events are processed as the events are processed as pressed/releasespressed/releases
public void mouseEntered(MouseEvent e) { }public void mouseEntered(MouseEvent e) { }-- entry into component-- entry into component
public void mouseExited(MouseEvent e) { }public void mouseExited(MouseEvent e) { }-- exit from component-- exit from component
public void mousePressed(MouseEvent e) { }public void mousePressed(MouseEvent e) { }-- simply a press . . .-- simply a press . . .
public void mouseReleased(MouseEvent e){ }public void mouseReleased(MouseEvent e){ }-- ... the corresponding release-- ... 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;frame.setSize(400,400);Button b = new Button("Click");b.addMouseListener(this);fr.setBackground(normal);fr.setLayout(new FlowLayout());fr.add(b); fr.show();
}
public static void main(String[] args) {new MouseFrame();
}
To keep it simple,we ignore
WindowEvents
Note that whenwe run this theconstructor willrun and terminate(more)
public void mouseReleased(MouseEvent e){System.out.println ("Changing color");if (bHighlight)
frame.setBackground(highlight);else
frame.setBackground(normal);bHighlight = !bHighlight;
}
public void mouseClicked(MouseEvent e) {}public void mouseEntered(MouseEvent e) {}public void mouseExited(MouseEvent e) {}public void mousePressed(MouseEvent e) {} } // MouseFrame
“click”
“click”
Event Listener SummaryEvent Listener Summary
We need a class that implements the appropriate listener type.
We need to “register” a component as interested in receiving events:
addXYZXYZListener ( <listener instance> );
Whatever listener we’re working with. E.g.:
addMouseListener(this);addMouseMotionListener(myEventHandler);
There’s another strategy using “adapters”, using inheritance that could have saved us some trouble...
ObservationsObservations
The “WindowListener” interface required numerous methods.
But only one was important to us.
All the rest were coded as “no-op” or no operation methods.
1111
2222
3333
AdaptersAdapters
public class MouseAdapter implements MouseListener {public class MouseAdapter implements MouseListener { public void mouseClicked(MouseEvent e) {}public void mouseClicked(MouseEvent e) {} public void mouseEntered(MouseEvent e) {}public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {}public void mouseExited(MouseEvent e) {} public void mousePressed(MouseEvent e) {}public void mousePressed(MouseEvent e) {} public void mouseReleased(MouseEvent e) {}public void mouseReleased(MouseEvent e) {}}}
Java has built-in classes called “event adapters” that implement each of the various event listeners.
But all of these methods are “no-ops”.
WHY?WHY?
Strategy
StrategyNo. 2No. 2
Key to Adapters: InheritanceKey to Adapters: Inheritance
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”
MouseFrame
MouseAdapter
Parentclass takes
care ofthese
import java.awt.*;import java.awt.event.*;public class MouseFrame extends MouseAdapterextends 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(); } public void mouseClicked(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} public void mousePressed(MouseEvent e) {}
Example (cont’d)Example (cont’d)
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
We overridethe one or
two methodswe care about
Same behavior; less code;but we use up our single inheritance
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
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) {}}
This comes with Java!
Big Picture TimeBig Picture Time
So far, we’ve tinkered(kurcalamak)with different ways of codingvery low-level event handling. But what if our event handling needs are very general.
Consider this simple dialog box:
cancel
Are you sure you wishto proceed ?
There’s not much interactionthat needs to be supported.
Mouse entry/exit might notbe needed at all.
ok
Semantic EventsSemantic Events
public void mouseClicked(MouseEvent e) {}public void mouseClicked(MouseEvent e) {}public void mouseEntered(MouseEvent e) {}public void mouseEntered(MouseEvent e) {}public void mouseExited(MouseEvent e) {}public void mouseExited(MouseEvent e) {}public void mousePressed(MouseEvent e) {}public void mousePressed(MouseEvent e) {}public void mouseReleased(MouseEvent e) {}public void mouseReleased(MouseEvent e) {}
Wouldn’t it be convenient to abstract all of these smallevents into one “just-tell-me-when-its-clicked” event?
public void actionPerformed(ActionEvent e)public void actionPerformed(ActionEvent e)
M1A1 Abstractor
Semantic EventsSemantic EventsStrategy
StrategyNo. 3No. 3
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 EventsSemantic Events
Note: ALLALL input is sent into one of these FOURFOUR categories.
Semantic Event Components and Firing Event
ActionEvent Button (activated)List (double-clicked)MenuItem (selected)TextField (typed)
AdjustmentEvent Scrollbar (moved)
ItemEvent Checkbox (toggled)CheckboxMenuItem (selected)Choice (selected)List (selected)
TextEvent TextComponent (text changes)
There are numerousevent handlers for low-level events
associatedwith these widgets.
ExampleExampleimport 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)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 fine-grained events (e.g., mouse entry/exit). But that might be acceptable for certain applications.
• 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 notnot 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.
(non) Option #4: JDK 1.02 Events(non) Option #4: JDK 1.02 EventsStrategy
StrategyNo. 4No. 4
Event Listeners(interfaces)
Event Adapters(inheritance)
Semantic Events
Costs Benefits
Must code allmethods; wastefulno-ops result
Uses up singleinheritanceopportunity
Simplifiesevent handling
Loss ofgranularcontrol;linear code
Keep allevents insingle class
Good abstraction;override those methodsyou need
Event Handling Options: How to DecideEvent Handling Options: How to Decide
DebuggingDebugging re: Event Handlersre: 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 HandlersDebugging 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.
To compare the three event handling techniques, let’s see a *brief* example how all three might work on a common problem.
Events: A Short ExampleEvents: A Short Example
My Program
BUTTON
TEXT AREA
Panel subclass
Goal: Create asimple Frame thatholds a TextAreaand Button.
The Button togglesthe ability to editthe TextArea
The Panel The Panel holding the holding the Button and Button and TextArea is TextArea is placed in a placed in a Frame Frame subclass, which subclass, which handles its own handles its own disposaldisposal
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);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) {}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) {}
}// class MyFrame
Constructor
WindowListener
Frames are not self-disposing!(Setting Frame invisible first
eliminate flicker.)
import java.awt.*;import java.awt.event.*;public class MyFrame extends Frame { public static final int
iWidth = 300,iHeight = 500;
public MyFrame() {
this.setSize(iWidth, iHeight);this.addWindowListener (new WindowAdapter() {
public void windowClosing (WindowEvent e) {
e.getWindow().setVisible(false);e.getWindow().dispose();System.exit(0);
} });BorderLayout border = new BorderLayout();this.setLayout(border);
}}// class MyFrame
“Anonymous Inner Class”:
used as a shortcut. For your
code, use listeners
Frames are not self-disposing!(Setting Frame
invisible firsteliminate flicker.)
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 TIEDTO THIS PROGRAM!
import java.awt.*;import java.awt.event.*;class Notepad extends Panel implements MouseListener{ Button toggle; TextArea scratch; boolean bWritable; public Notepad() {
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
Variation #1: Listener Events Variation #1: Listener Events (MouseListener)(MouseListener)
The Driver and MyFrame classes weregeneric enough to work with any
version of this example. Here, however, we need to create a specific event handler.
/* . . . Continued from “class Notepad extends Panel implements MouseListener” . . . */
public void setWritable(boolean bWritable){this.bWritable = bWritable;
}//setWritable
public boolean getWritable() {return bWritable;
}//getWritable
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
Implement themethod one needs;
the rest are “no-ops”
Driver main Notepad note MyFrame f
Notepad extends Panel Button toggle TextArea scratch boolean bWritable
My Program
BUTTON
TEXT AREA
Variation #2: Adapter Events Variation #2: Adapter Events (MouseAdapter)(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);
toggle.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e)
{ getTextArea().setEnabled(getWritable()); setWritable(!getWritable());}
});/* end of anonymous inner class */
bWritable = false; }// constructor
Note useof anonymous
inner class.
Variation #3: Another Way!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 WayVariation #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
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
Variation #4: Semantic Events Variation #4: Semantic Events (ActionListener)(ActionListener)
/* . . . 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 ReviewEvent Handlers: Final Review
This simple example shows that sometimes, semantic event handlersperform the task perfectly.
In the drawing applet example, the semantic event handler was unableto 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 CommunicationCross 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?) ExampleAnother (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 MethodThe Madness HAS-A Method
EventHandler(a MouseListener)
FlashDemo(a JFrame)
Makes an array ofJButtons...
... sets their event handler, passing
in “this” and the button.
Saves the frame andbutton reference . . .
... so it can call back tothe frame to set
its title, and changethe 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;
public FlashDemo () {this.addWindowListener(this);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);
}
Key MethodCall
/* 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 madethis 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...Additional Presentation...
Questions?Questions?