Class java.awt.Event object can represent all Java events. It has a field id which indicates the type of the event - a mouse down/up, ASCII key pressed/up, Non-ASCII key (e.g. F1, Delete key) pressed/up, a component lost/got focus, etc. For any of these events, it has a static enum. Therefore, to find out exactly what happens in your event handling method, you may have to use cascaded if statements such as
if(e1.id == Event.KEY_PRESS)
to find out what happens. This is a non-OO approach.
When an ASCII key is pressed, Event . id has a value of KEY_PRESS as indication, and field key holds the unicode value of that key (e.g., for 'a' it is 97, 'b' 98, etc.). For the non-ASCII keys, key will hold corresponding static constants representing their value (e.g., Event.F1 for F1 key).
The Java toolkit creates all events. Ultimately, the OS is responsible for reporting events coming from the keyboard, mouse etc. These events are then passed to the Toolkit, which determines which component the event belongs to (based on current focus, location of event etc.).
The old and the new event models are completely separate. All events in the old model are passed to handleEvent, but if a component is using the new model, handleEvent is not used at all. The way AWT finds out what model a component is using is: only when a component has registered the corresponding listeners, or have explicitly enabled the events using enableEvents, will it be regarded as using new event model, and the corresponding events be sent to it. If none of this happens, the component is regarded as using old event model.
Java 1.0 method. Already deprecated. When an event happens, an Event object is created, and the handleEvent method of the Component on focus is called and the Event object is passed to it. You can then implement this method and do whatever you like to handle the event. When you have more than one possible events, you have to use cascaded if statements in handleEvent.
Among all old-style events, there are a small groups of "standard" events related to buttons, checkboxes, drop-down lists, menus, key down, got/lost focus, mouse down/up/move/drag/enter/exit, etc. When this events are passed to handleEvent, it will automatically call the corresponding methods such as
action(Event, Object)
keyDown(Event, int key)
keyUp(Event, int key)
lostFocus(Event, Object)
gotFocus(Event, Object)
mouseDown(Event, int x, int y)
mouseUp(Event, int x, int y)
mouseMove(Event, int x, int y)
mouseDrag(Event, int x, int y)
mouseEnter(Event, int x, int y)
mouseExit(Event, int x, int y)
If you only want to handle some of these standard events, you needn't implement handleEvent. You only need to implement these standard event handling methods.
Especially, method action will be called by handleEvent when events of those standard components such as buttons, checkboxes, drop-down lists, menus happen.
All these methods have a return type as boolean, which indicates whether the passed event has been handled. Among all the above methods, only handleEvent and action is designed for handling more than one kinds of events, so in these two methods a cascaded if structure is needed to check what kind of event it is. Suppose in a handleEvent or an action you are only interested in one or several kinds of events, then at the last else branch you should call the super class's handleEvent or action to let it handle the unhandled event. For the rest of the methods, you can always return true, because they are only called by handleEvent when the exact type of event is passed to handleEvent.
Old event model has only one Event class to represent all events. To find out what kind of event (standard component event from Buttons, TextFields, Lists, etc., or keyboard event, mouse event etc.) in your event handling code, you have to use cascaded if statements. This is a non-OO approach.
Java 1.1 provides a set of events in package java.awt.event representing different types of events.
As said before, if you do not do anything to a component, this component will be treated by AWT as using old event model, and all events will be sent to its handleEvent method. To enable new event model for a component, you have to either explicitly or implicitly call method enableEvent. When you register one type of event listener to a component by calling add___Listener, it will implicitly call enableEvent with the corresponding event mask.
Only the event with registered listener or enabled events will be sent to the component.
New Java divide all events into several categories:
Event |
Event Description |
Event Originators |
EventListener Methods |
ActionEvent |
a component-defined action occurred. This high-level event is generated by a component (such as a Button) when the component-specific action occurs (such as being pressed). |
Button, List, TextField, MenuItem, and its derivatives including CheckboxMenuItem, Menu, and PopupMenu |
actionPerformed |
Adjustment Event |
The adjustment event emitted by Adjustable objects. |
Scrollbar or anything you create that implements the Adjustable interface |
adjustmentValueChanged |
ChangeEvent |
The thumb on the slider is moved. |
JSlider |
stateChanged |
Component Event |
A low-level event indicating that a component moved, changed size, or changed visibility (also, the root class for the other component-level events). Component events are provided for notification purposes ONLY; The AWT will automatically handle component moves and resizes internally |
Component and its derivatives, including Button, Canvas, Checkbox, Choice, Container, Panel, Applet, ScrollPane, Window, Dialog, FileDialog, Frame, Label, List, Scrollbar, TextArea, and TextField |
componentHidden |
Container Event |
A low-level event indicating that a container's component was added or removed. For notification purposes ONLY |
Container and its derivatives, including Panel, Applet, ScrollPane, Window, Dialog, FileDialog, and Frame |
componentAdded |
FocusEvent |
A component has gained or lost the keyboard focus. Generated by a component (such as a text field). |
Component and its derivatives, including Button, Canvas, Checkbox, Choice, Container, Panel, Applet, ScrollPane, Window, Dialog, FileDialog, Frame Label, List, Scrollbar, TextArea, and TextField |
focusGained |
ItemEvent |
An item was selected or deselected. Generated by an ItemSelectable object (such as a List) when an item is selected or de-selected. |
Checkbox, CheckboxMenuItem, Choice, List, and anything that implements the ItemSelectable interface |
itemStateChanged |
KeyEvent |
A keystroke occurred in a component. Generated by a component object (such as a text field) when a key is pressed, released, or typed. |
Component and its derivatives, including Button, Canvas, Checkbox, Choice, Container, Panel, Applet, ScrollPane, Window, Dialog, FileDialog, Frame, Label, List, Scrollbar, TextArea, and TextField |
keyPressed |
ListSelectionEvent |
An item in a JList has been selected. |
JList |
(ListSelectionListener) valueChanged |
MouseEvent |
A mouse action occurred in a component. Used both for mouse events (click, enter, exit) and mouse motion events (moves and drags). |
Component and its derivatives, including Button, Canvas, Checkbox, Choice, Container, Panel, Applet, ScrollPane, Window, Dialog, FileDialog, Frame, Label, List, Scrollbar, TextArea, and TextField |
(MouseListener) mouseClicked |
Dito |
Dito |
Component and its derivatives, including Button, Canvas, Checkbox, Choice, Container, Panel, Applet, ScrollPane, Window, Dialog, FileDialog, Frame, Label, List, Scrollbar, TextArea, and TextField |
(MouseMotion Listener) mouseDragged |
TextEvent |
A semantic event which indicates that an object's text changed. Generated by an object (such as a TextComponent) when its text changes. |
Anything derived from TextComponent, including TextArea and TextField |
textValueChanged |
Window Event |
A low-level event which indicates that a window has changed its status. Generated by a Window object when it is opened, closed, about to close, activated or deactivated, iconified or deconified. |
Window and its derivatives, including Dialog, FileDialog, and Frame |
windowOpened |
The follow table lists all the events that a component can fire:
Component |
Events supported by this component |
Adjustable |
AdjustmentEvent |
Applet |
ContainerEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent |
Button |
ActionEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent |
Canvas |
FocusEvent, KeyEvent, MouseEvent, ComponentEvent |
Checkbox |
ItemEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent |
CheckboxMenuItem |
ActionEvent, ItemEvent |
Choice |
ItemEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent |
Component |
FocusEvent, KeyEvent, MouseEvent, ComponentEvent |
Container |
ContainerEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent |
Dialog |
ContainerEvent, WindowEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent |
FileDialog |
ContainerEvent, WindowEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent |
Frame |
ContainerEvent, WindowEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent |
JList |
ListSelectionEvent |
JSlider |
ChangeEvent |
Label |
FocusEvent, KeyEvent, MouseEvent, ComponentEvent |
List |
ActionEvent, FocusEvent, KeyEvent, MouseEvent, ItemEvent, ComponentEvent |
Menu |
ActionEvent |
MenuItem |
ActionEvent |
Panel |
ContainerEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent |
PopupMenu |
ActionEvent |
Scrollbar |
AdjustmentEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent |
ScrollPane |
ContainerEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent |
TextArea |
TextEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent |
TextComponent |
TextEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent |
TextField |
ActionEvent (when enter is pressed), TextEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent |
Window |
ContainerEvent, WindowEvent, FocusEvent, KeyEvent, MouseEvent, ComponentEvent |
For each type of event, there is a corresponding listener interface with relevant methods to handle this specific event. Events are "fired" by every kind of components (keyboard events are fired by OS through Java toolkit).
When you use a component, you must call that component's relevant add___Listener method to register the objects to which you want to deliver the fired event, so that they can receive this event and handle it. Fore example, if you expect a component to fire TextEvent, you should call its addTextListener to register an TextListener object.
For all objects who want to be notified of a certain type of event, they must implement the corresponding Listener interface. For example, if an object want to listen to TextEvent, it must implement interface TextListener.
A listener can either be an independent class with other functionality, who would simply like to be notified when something happened far away, or a class specially designed to handle this event. The later one can be more precisely called an event handler. It is a good idea to make an event handler an inner class inside the event originator. It is not only because logically it's better to group the event handler together with the originator, but also because the event handler may very probably need to access the data members of the originator, and an inner class can directly access them. Such an event originator can be called a self-contained event originator. It includes all event handling inner classes.
Normally, for each event originator object, even if they are of the same type and fires the same type of events, e.g., two buttons "OK" and "Exit", they should still have their own separate event handlers - after all, that's why we make two buttons instead of one. But it is not always necessary to do that. If you one event handler can gracefully handle all events, you can have one.
All event objects inherits from EventObject. It keeps a reference to the object who fires it. It has a getSource method to return the event originator.
Under new event model, all events are first sent to the component's processEvent method. This method will identify the type of the event, and send it. Normally the whole process of event distribution happens internally and implicitly. What programmers need to do is to simply provide event handlers to receive events at the end of the route. However, if we want to do some thing before events are classified into specific types, we have to know the distribution process. The event distributing process has two steps:
Any enabled event which happens over a component (not over the components it holds) will cause the processEvent method of that component be called. This is the mere entry point of an event into the distributing process. By default processEvent will identify the specific type of the event and call the corresponding process___Event method.
For example, if a ComponentEvent happens, processEvent will be called and it will call processComponentEvent.
There are the following process___Event methods in Component:
processComponentEvent (java.awt.event.ComponentEvent),
processFocusEvent (java.awt.event.FocusEvent), processKeyEvent(java.awt.event.KeyEvent),
processMouseEvent (java.awt.event.MouseEvent),
processMouseMotionEvent (java.awt.event.MouseEvent),
processInputMethodEvent (java.awt.event.InputMethodEvent),
processHierarchyEvent (java.awt.event.HierarchyEvent)
For Component's subclasses, they may have more such methods, e.g., Window has an extra processWindowEvent method.
The process___Event method will then by default deliver the Event to all registered Listeners of that type. For example, processFocusEvent will deliver the FocusEvent to FocusListeners.
As said before, the whole event distribution process happens internally and implicitly, and programmers only need to provide event handlers to receive events at the end of the route. This way you seldom need to make use of the passed event object, because this listener is often designed for a specific component such as a button, the listener already knows exactly what happens. It is only concerned with "what to do", not "what happened" (of course for KeyEvents you may still have to use getKeyCode to check which key is pressed, but you do not need cascading if). This is more OO, and easy to write, reuse and debug.
When you want to change the event distribution process, or attach more functionalities to it, then you have to override method processEvent and/or precess___Event. If you decide not to use event listeners to handle events, instead you want to handle thoes events in processEvent or precess___Event, you have to explicitly enable events using enableEvent. This way you often have to use the non-OO cascading if structure, the event handling code is more coupled with the other programs, so it is difficult to write, debug and reuse, and you have to call super.process___Event - this reminds us of the old event model.
import java.awt.*; import java.awt.event.*; class Frame1 extends Frame { Button b1 = new Button("Button"); public Frame1() { add(b1); addWindowListener(new WindowClosingHandler()); // This enabled WindowEvent enableEvents(AWTEvent.KEY_EVENT_MASK | AWTEvent.FOCUS_EVENT_MASK); // This enabled KeyEvent and FocusEvent setSize(200,200); show(); } // Level 0 event handling public void processEvent(AWTEvent e1) { System.out.print("Event -- "); super.processEvent(e1); } // Level 1 event handling public void processWindowEvent(WindowEvent e1) { System.out.println("WindowEvent!"); super.processWindowEvent(e1); } public void processKeyEvent(KeyEvent e1) { System.out.println("Pressed: " + KeyEvent.getKeyText(e1.getKeyCode())); super.processKeyEvent(e1); } public void processFocusEvent(FocusEvent e1) { System.out.println(e1.paramString()); super.processFocusEvent(e1); } // Level 3 event handling class WindowClosingHandler extends WindowAdapter { public void windowClosing(WindowEvent e1) { System.exit(0); } } } public class Test { public static void main(String [] args) { Frame1 f1 = new Frame1(); } }
The following InputFilename.java is a class designed for our assignment. It is a dialog used to prompt user to input a filename.
import java.awt.event.*; import java.awt.*; class InputFilename extends Dialog { TextField t1 = new TextField("Test", 15); Choice c1 = new Choice(); Button b1 = new Button(" OK "); Button b2 = new Button("Cancel"); Label l1 = new Label("Please input filename..."); Label l2 = new Label("File type..."); String filename = ""; String [] extension = {".txt", ""}; public InputFilename(Frame parent) { super(parent, "Input Filename", true); initialise(); } public InputFilename(Dialog parent) { super(parent, "Input Filename", true); initialise(); } public void initialise() { addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e1) { dispose(); } }); b1.addActionListener(new OKListener()); b2.addActionListener(new CancelListener()); c1.add("Text"); c1.add("All types"); c1.select("Text"); setLayout(new FlowLayout()); add(l1); add(t1); add(l2); add(c1); add(b1); add(b2); setSize(200,150); setResizable(false); show(); } public String getFilename() { return filename; } class OKListener implements ActionListener { public void actionPerformed(ActionEvent e1) { if(!t1.getText().equals("")) { filename = t1.getText() + extension[c1.getSelectedIndex()]; dispose(); } } } class CancelListener implements ActionListener { public void actionPerformed(ActionEvent e1) { dispose(); } } } public class Test{ public static void main(String [] argu) { Frame f1 = new Frame(); InputFilename n1 = new InputFilename(f1); System.out.println("Filename is:\n" + n1.getFilename()); } }
Class java.awt.event.InputEvent is the root event class for all component-level input events. Input events are delivered to listeners before they are processed normally by the source where they originate. E.g., when you type into a TextField, the KeyEvent is delivered to a registered KeyListener before the TextField actually displays the typed character.
This allows listeners and component subclasses to "consume" the event so that the source will not process them in their default manner. For example, if a KeyListener has its own way to handle the key press and do not want the TextField to directly display the typed character (e.g. when handling password input), it can call the consume method of the passed event object. Then when the event handling completes and control returns to the event originator - the TextField, it will not display that character as usual. If consume is not called, it will display the character in spite of what the listener has done.
All events we've been discussing before are standard Java events - they are generated automatically by the OS or JVM and dispatched to the processEvent method of the current component. But what if we want a group listeners to be notified when some thing happens in a piece of code which does not generate any standard Java event? Java provides this Observer - Observable pattern in package java.util to solve this problem.
One common application is when you have a data model and several views of this model. Once the model is changed, you hope the views will automatically update themselves. This "model-view" problem can be solved with this pattern.
Class java.util.Obserable which represents the data model. It has an addObserver method to register Observers to itself. If any one wants to notify the registered Observers of the Observable class with an Object carrying nessary information, he should call its notifyObservers method with that object as argument.
Used to register all the view i.e. Observer objects which should be notified when this Observable objects is considered "changed".
Set the status of the Observable object to "changed". Note that this method is protected, so it is not accessible by outside clients. When something of the Observable is changed that all Observers should know, setChanged( ) method should be called.
Check the status of this Observable object.
Set the status of this Observable object to "unchanged".
This method is called to notify all registered Observers to update themselves. It will first check if hasChanged( ) returns true. If not, nothing will be done. Then this method will call all each Observer's update(Observable o, Object argu) method, passing itself and the "argu" object as arguments.
After Observer's update( ) is finished, control will go back to notifyObservers( ). Then clearChanged( ) will be called to set the status of the object back to "unchanged".
This method can either be called by outside clients when they think necessary to update the observers, or more automatically be called by the method which make essential changes on this Observable object, after it has called setChanged( ).
Therefore, if you want your class to be able to notify a list of observers, you should let it extend Observable, and at the point where a change to the object is made which is considered to be essential, call the setChanged( ) method of underlying Observable class, and the notifyObservers( ) method - if you want the notifying process to start automatically every time the Observable is changed.
Observer is an interface with only one method:
public void update(Observable o1, Object argu)
If you want your object to be notified when another object somewhere else is changed, you should let your object implement Observer interface and its update( ) method, doing in this method whatever you think is necessary as a response to the change. The client of your object should also register your Observer object to the Observable object.
The arguments of the update( ) method are:
Observable o1: the one who notify you.
Object argu: the extra object passed by the caller of the notifier's notifyObservers( ).
import java.util.*; class DataModel extends Observable { private String name; public DataModel(String s) { name = s; } public void change() { super.setChanged(); super.notifyObservers(name); } } class Windows implements Observer { private String name; public Windows(String s) { name = s; } public void update(Observable o1, Object argu) { System.out.println("\n" + name + " get notified by \"" + argu + "\" of " + o1.getClass().toString()); } } public class Test { public static void main(String[] argu) { DataModel model = new DataModel("Model"); Windows window1 = new Windows("Window 1"); Windows window2 = new Windows("Window 2"); model.addObserver(window1); model.addObserver(window2);
System.out.println("\"Model\" has " + model.countObservers() + "
observers!\n"); System.out.println("Has \"Model\" been changed? "+ model.hasChanged()+ "\n"); System.out.println("Now changing \"Model\"..."); model.change(); System.out.println("\nHas \"Model\" been changed? " + model.hasChanged() + "\n"); } }
Output will be:
"Model" has 2 observers! Has "Model" been changed? false Now changing "Model"... Window 2 get notified by "Model" of class DataModel Window 1 get notified by "Model" of class DataModel Has "Model" been changed? false