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. componentsevents listeners registration 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. delegation eventevent filtration model 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 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 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.
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 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 The code we wrote in main() and other methods 2 The code Java provides to handle the graphics side of things. Graphics Your Code
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 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” 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”. callback Our event handling code The code trapping this event appears in the graphics thread
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 callback 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! 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. 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 public void actionPerformed (ActionEvent e) { // code doing something } This method MUST be there, so Java knows it can “callback” to it ActionListener
Why “Delegation”? “delegate” 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? Some (smart) folks believe you should organize where the events get handled. (This is the “controller” aspect to MVC.) M C V
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?
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 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: Keyboard events Timing events Mouse events Other user action inputs a b c d
Java Event Handling Strategies With this basic understanding, we can investigate the FOUR FOUR primary means of event handling in Java Event Adapters Semantic Events Event Listeners Inheritance-based event handling Very similar Very general Very old You are 100% guaranteed to have a quiz question on this
ListenersStrategy No. 1 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...
Most commonly used Yikes. 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...
MouseListener The MouseListener interface has several methods we have to code: public void mouseClicked(MouseEvent e) { } public void mouseClicked(MouseEvent e) { } -- a timing-based determination; else the events are processed as the events are processed as pressed/releases pressed/releases public void mouseEntered(MouseEvent e) { } public void mouseEntered(MouseEvent e) { } -- entry into component public void mouseExited(MouseEvent e) { } public void mouseExited(MouseEvent e) { } -- exit from component public void mousePressed(MouseEvent e) { } public void mousePressed(MouseEvent e) { } -- simply a press... public void mouseReleased(MouseEvent e){ } 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; 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 when we run this the constructor will run 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”
Event Listener Summary We need a class that implements the appropriate listener type. We need to “register” a component as interested in receiving events: XYZ addXYZListener ( ); 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...Observations 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
Adapters 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?Strategy No. 2
Key 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
Parent class takes care of these import java.awt.*; import java.awt.event.*; extends MouseAdapter 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(); } public void mouseClicked(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} public void mousePressed(MouseEvent e) {}
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 override the one or two methods we 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 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: cancel Are you sure you wish to proceed ? There’s not much interaction that needs to be supported. Mouse entry/exit might not be needed at all. ok
Semantic Events 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) {} Wouldn’t it be convenient to abstract all of these small events into one “just-tell-me-when-its-clicked” event? public void actionPerformed(ActionEvent e) M1A1 Abstractor
Semantic Events Strategy No. 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 Events ALLFOUR Note: ALL input is sent into one of these FOUR categories. Semantic EventComponents and Firing Event ActionEventButton (activated) List (double-clicked) MenuItem (selected) TextField (typed) AdjustmentEventScrollbar (moved) ItemEventCheckbox (toggled) CheckboxMenuItem (selected) Choice (selected) List (selected) TextEventTextComponent (text changes) There are numerous event handlers for low-level events associated with these widgets.
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 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 not 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 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 Strategy No. 4
Event Listeners (interfaces) Event Adapters (inheritance) Semantic Events Costs Benefits Must code all methods; wasteful no-ops result Uses up single inheritance opportunity Simplifies event handling Loss of granular control; linear code Keep all events in single class Good abstraction; override those methods you need Event Handling Options: How to Decide
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.
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 Example My Program BUTTON TEXT AREA Panel subclass Goal: Create a simple Frame that holds a TextArea and Button. The Button toggles the ability to edit the TextArea 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); 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 short cut. For your code, use listeners Frames are not self-disposing! (Setting Frame invisible first eliminate 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 TIED TO 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 (MouseListener) The Driver and MyFrame classes were generic 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 the method 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 (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 use of anonymous inner class.
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
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 (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 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 EventHandler (a MouseListener) FlashDemo (a JFrame) Makes an array of JButtons sets their event handler, passing in “this” and the button. Saves the frame and button reference 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; 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 Method Call
/* 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?