next up previous contents
Next: Reflection Up: Event driven programming Previous: The event queue   Contents

Custom events

Just like we can add new types of exceptions in a Java program, we can also define new types of events. Let us look at how to add a new type of event called TimerEvent to be generated by a Timer object.

Events in Java (generally) extend the class AWTEvent. Each distinct type of event has a unique numeric identifier. We can thus write

  class TimerEvent extends AWTEvent{

     public static final int
         TIMER_EVENT = AWTEvent.RESERVED_ID_MAX + 5555;

     public TimerEvent(Timer t) { 
       super(t, TIMER_EVENT); 
     }
  }

Here, we use a language defined constant that delimits the numeric identifiers in use for built-in events to ensure that our new event does not clash with any of the built-in events. The constructor essentially sets two quantities: the source of the event and the (numeric) type of the event.

Next, we define an interface that specifies the functions that a listener for TimerEvent must implement. This might be as follows

   interface TimerListener extends EventListener{  
      public void timeElapsed(TimerEvent evt);
   }

Now, we can make the class Timer generate such events by explicitly manipulating the event queue, as described earlier.

   class Timer extends Component implements Runnable{
      // Runnable is to ensure that Timer can run concurrently
      ...
      private static EventQueue evtq = 
             Toolkit.getDefaultToolkit().getSystemEventQueue();
      // There is only one copy of the EventQueue, shared by all Timers

      public Timer(){
        ...
      }

      public void f(){
         ...
         // Generate a TimerEvent when done 
         TimerEvent te = new TimerEvent(this); 
         evtq.postEvent(te);   
      }
   }

Of course, we need a class that listens to TimerEvents, so we have

   class MyClass implements TimerListener{
      ...
      public void timeElapsed(TimerEvent evt){
        ...
      }
   }

We need to inform the Timer object of the existence of a specific listener object from MyClass. For this, we have to add the following in Timer.

   class Timer extends Component implements Runnable{
      ...
      private TimerListener listener;

      public addListener(TimerListener t){
        listener = t;
      }
      ...
   }

In other words, it is the duty of the Timer object to keep track of the listeners it has to notify. This is the general Java philosophy, which is why we have methods like addActionListener(..) for JButtons etc.

Assume now that we have code like the following:

    ...
    Timer t = new Timer();
    MyClass m = new MyClass(..);
    t.addListener(m);
    t.f();
    ...

At the end of t.f(), how does t know what it has to do to notify m? The answer is that it does not. This has to be programmed in the definition of Timer. What the AWT system provides is the name of a fixed function called processEvent that will be called within an object whenever it generates an AWTEvent. We can now add the following code in Timer.

   class Timer extends Component implements Runnable{
      ...

      public void processEvent(AWTEvent evt)
      {  if (evt instanceof TimerEvent)
         {  if (listener != null)
               listener.timeElapsed((TimerEvent)evt);
         }
         else super.processEvent(evt);
      }  
      ...
   }

Now, all the pieces are in place. When a Timer t generates a TimerEvent, AWT calls the (fixed) method processEvent within t. This provides the explicit code with which to call any listener associated with t. Notice that instead of one TimerListener, we could have defined Timer to store an array of listeners and notified each of them in turn, thus supporting multicasting.

The same general architecture drives the functioning of builtin objects like JButton etc. Externally, it appears as though the run-time environment ``knows'' that when a JButton is pressed, the correct method to invoke in an ActionListener is actionPerformed. However, all that the button press event does is to invoke processEvent in the JButton object that is pressed. The definition of JButton, like the definition that we have just given for Timer, includes all the necessary information about its listeners and the methods to use to notify these listeners that the button has been pressed.


next up previous contents
Next: Reflection Up: Event driven programming Previous: The event queue   Contents
Madhavan Mukund 2004-04-29