| SCOUG OS/2 For You - May 1999
 Cup of JavaEvent Handling
One of the most important aspects of most non-trivial applications (especially UI type apps) is the ability to respond to events that are generated by the various components of the application, both in response to user interactions and other system components such as client-server processing. In this article we will look at how Java supports event generation and handling and how to create (and process) custom events.
 Event BasicsThere are three parts to the event model in Java 1.1. They are:
 
(1)  Event object
this is an instance of a Java class  that contains the characteristics of the event. For  example, if the event is generated from clicking  a mouse button, the event object would contain  information such as the coordinates of the  mouse cursor, which button was clicked, how  many times it was clicked, etc..
(2) Dispatching class/method
this is an object  which detects that an event has occurred and is  then responsible for notifying other objects of  the event, passing the appropriate event object  to those objects. These other objects are  "listeners" for the event. Most AWT  components, such as Button, List, Textfield, etc.  are examples of dispatching classes. 
 A Button, for instance, is capable of notifying  other components when it is "pushed."  These classes will typically have a set of two methods  that can be invoked by would-be "listeners": one  to tell the class that the object wants to listen  and another to tell the class that the object no  longer wants to listen.
  These methods are conventionally named:
add...Listener  (to add an object as a listener)
 remove...Listener (to remove the object as a   listener)
 where ... is the generic type of event to listen  for. In the case of the Button, this would be "Action" to indicate the action of pushing the  button. (So the methods would be  addActionListener and removeActionListener).
 
(3) Listener Interface
for the dispatching to work  properly, the dispatching class must be able to  rely on each of its listeners to contain the  method that it executes when the event occurs.  This is easily accomplished in Java through the  use of an Interface class. The details of the  interface are determined by the type of events  that it supports.
 The important point is that a class which is  going to be a listener must implement that  interface (which in turn means that it must  define all of the interface's methods).
 A Simple Example
 The AWT Button class can be used to demonstrate the use of events. As mentioned above, the Button class generates an ActionEvent when "pushed." Since the Button class itself generates and dispatches these events, you only need to tell a button that you want to be notified and then code the required interface method; in this case there is only one. The interface associated with ActionEvent is ActionListener and its one method is Action-Performed.
 (NOTE: all of the AWT events are defined in the package named java.awt.event for JDK 1.1.)
 So, the following code would be added to your class to allow it to perform processing when a button is pushed:
import java.awt.*;
import java.awt.event.*;
// define a Frame and allow it to handle Action events
public class MyClass 
extends Frame implements ActionListener
// define a Button object
   Button myButton = new Button(...)
// tell the Button object that the Frame component is to
// be notified when the button is pushed:
   myButton.addActionListener(this);
// add the required method for the ActionListener
// interface
  public void ActionPerformed(ActionEvent aev) {
// specific processing in the method for the myButton
// object
    if (aev.getSource() == myButton) {
       ... processing
       return;
    } Event CategoriesFor the AWT package, there are a number of events supported.  These events are broken down into categories that loosely represent the types of actions that a GUI application needs to process. The events and their listener interfaces are actually defined in another package, awt.event. 
 It is not practical to list the details here, but the categories are:
 
ActionEvent
handles controls that can be  "pushed" such as buttons and menu items
AdjustmentEvent
handles controls that are  "adjustable" such as a Scrollbar
ComponentEvent
handles component level events  such as moving, resizing, displaying, etc.
ContainerEvent
handles container level events  such as adding or removing components
FocusEvent
handles focus gained or lost events
ItemEvent
handles selectable controls such as  List, Choice
KeyEvent
handles keyboard events
MouseEvent
handles mouse button events and mouse movement into or out of a component
MouseMotionEvent
handles mouse drag and  movement events
TextEvent
handles text component events such as  text changed
WindowEvent
handles generic window events  such as open, close, activate and deactivate
 What if I'm lazy?
 Sometimes coding all of the methods for an interface can be time consuming (or at least boring); especially when you are just interested in one of them. To simplify this effort, the JDK provides a pre-defined set of classes called Adapters which define all of the methods for the corresponding Listener interface, each of which does nothing. You can then simply create your own subclassed version of the Adapter and override the one (or two) methods that you are interested in.
 For example, to implement only the MousePressed method you could define a class such as:
public class MyMouseAdapter extends MouseAdapter {
    public void mousePressed(MouseEvent e) {
      ... custom processing ...
    }
  } Custom EventsThe above information paves the way to understanding how to create our own custom event and handlers. Suppose we were building an application which interacts with the SCOUG membership database. We would have a specific class, AccessMembers, that does the actual database interaction, and another class ScougMember which contains the details of a specific member. We now want to set up event handling that will allow other parts of this application to do processing when the database is accessed.
 To accomplish this we would need to:
 (1) define an event class that encapsulates the information for the database interaction events (eg MemberEvent).  A sample, which provides the member class and status code (ie., whether the operation was successful or not) would be:
public class MemberEvent {
      private ScougMember member;
      private int statusCode;
      MemberEvent(ScougMember m, status s) {
        member = m;
        statusCode = s;
      }
      public ScougMember getMember() {
         return member;
      }
      public int getStatusCode() {
         return statusCode();
      }
    } (2) define an interface that supports the various forms of the event (eg MemberListener). For simplicity, we will just handle three forms:
add a new member (addMember method)
 modify an existing member (modifyMember  method)
 delete a member (deleteMember method)
 A sample definition:
public Interface MemberListener {
      public void memberAdded(MemberEvent mv);
      public void memberModified(MemberEvent mv);
      public void memberDeleted(MemberEvent mv);
    } (3) add code to the AccessMembers class to support the creation of the MemberEvent and notification to all currently registered listeners. This can be somewhat complex, but the general requirements are:
//define a Vector to hold the currently active listeners:
    private Vector listeners = new Vector();
    //provide methods to add/remove listeners:
    public synchronized void addMemberListener(MemberListener ml) {
      listeners.addElement(ml);
    }
    public synchronized void removeMemberListener(MemberListener ml) {
       listeners.removeElement(ml);
    }
//add methods to notify listeners when the event occurs
//example here is when a member is modified:
    private synchronized void notifyModified(ScougMember m, status s) {
      MemberEvent mev = new MemberEvent(m, s);
      Enumeration en = listeners.elements();
      while (en.hasMoreElements()) {
        ((MemberListener) en.nextElement()).userModified(mev);
      }
    } (4) add code to the other components of the applica-tion to receive and process the MemberEvents. This coding is similar to the simple Button example given above:
public class Whatever implements MemberListener { ...
     
   //must have an access object (either set or passed)
   private AccessMember access;
        //something must set the access object:
        public void setAccessMember(am) {
          access = am;
        }
         ...
        //register this class to listen
        access.addMemberListener(this);
        //define all three methods of the interface
        public void userAdded(MemberEvent m) { ... }
        public void userModified(MemberEvent m) { ... }
        public void userDeleted(MemberEvent m) { ... } Then, the code in each of these three methods would automatically be invoked whenever the appropriate event occurred within the access object.
 SummaryEvent handling in JDK 1.1 is based on the concepts of event listeners and notifiers. For them to communicate properly, an Event object and Listener interface are used. This model provides a robust and extensible capability which can be applied to non-visual events as well as GUI ones.
 
 
Cup of Java by Terry Warren  started last month with 
Threads and Java.
Next month, the topic is Zipping Along.
 
 The Southern California OS/2 User Group
 P.O. Box 26904
 Santa Ana, CA  92799-6904, USA
 Copyright 1999 the Southern California OS/2 User Group.  ALL RIGHTS 
RESERVED. 
 SCOUG, Warp Expo West, and Warpfest are trademarks of the Southern California OS/2 User Group.
OS/2, Workplace Shell, and IBM are registered trademarks of International 
Business Machines Corporation.
 All other trademarks remain the property of their respective owners.
 |