CMSC 498B: Developing User Interfaces - Spring 2002

Event Handling

Handling events

 

Basic button interaction

  • Active/Inactive
  • Armed/unarmed
  • Pressed/unpressed
  • Fire when active, armed, and released

Windowing Systems

What is a Window Manager?  (Built-in like Windows compared to decoupled like X)

Efficiency issues of local vs. remote display server

What is a Window?  Root vs. internal widows.  Look at a window tree with Spy++.

Event Dispatching

Bottom-up

Top-down

Events

Event types

  • Mouse, Keyboard, window, etc.
  • Some events, like mouse motion, can be coalesced to avoid unnecessary extra events (see awt/Component.java coalesceEvents()).
  • Events have types, modifiers, and event-specific information

Event dispatching

  • Applications register a callback  event handler or "listener" that gets called when the event ocurrs.

Using Java Events

Use of interfaces and subclassing to organize events

  • AWTEvent - Source of an event, ID of an event

All of the classes:

  • XXXEvent
  • XXXEventListener
  • XXXEventAdapter

Use of events:

component.addMouseListener(new Mouse Adapter() {
    public void mousePressed(MouseEvent e) {
        System.out.println("mouse pressed");
    }
}

Example drawing program - Draw.java

Lots of events available - see the java.awt.event package

How to define custom events?  When would you use them?

  • See javax.swing.event.EventListenerList
 EventListenerList listenerList = new EventListenerList();
 FooEvent fooEvent = null;

 public void addFooListener(FooListener l) {
     listenerList.add(FooListener.class, l);
 }

 public void removeFooListener(FooListener l) {
     listenerList.remove(FooListener.class, l);
 }


 // Notify all listeners that have registered interest for
 // notification on this event type.  The event instance 
 // is lazily created using the parameters passed into 
 // the fire method.

 protected void fireFooXXX() {
     // Guaranteed to return a non-null array
     Object[] listeners = listenerList.getListenerList();
     // Process the listeners last to first, notifying
     // those that are interested in this event
     for (int i = listeners.length-2; i>=0; i-=2) {
         if (listeners[i]==FooListener.class) {
             // Lazily create the event:
             if (fooEvent == null)
                 fooEvent = new FooEvent(this);
             ((FooListener)listeners[i+1]).fooXXX(fooEvent);
         }
     }
 }

Full example: AlarmClock.java

Dispatching Java Events

Event loop pseudocode. 

while (not time to quit) {
    Event e = queue.nextEvent();
    dispatchEvent(e);
}

void dispatchEvent(Event e) {
    Window window = calculateWindowThatGetsEventBasedOnEvent(e);
    ListenerList list = eventTable.lookup(window, e.type);
    foreach (listener in list) {
        list.callback(e);
    }
}

Key events get percolated up unless consumed
See actual dispatch code in awt/Componet.java

Using C# Events

control.MouseDown += new MouseEventHandler(mouseDownHandler);

public void mouseDownHandler(object sender, MouseEventArgs e) {
    Console.WriteLine("mouse pressed");
}

Example drawing program - draw.cs

See events of Control class

How to define custom events?

using System;

//Step 1. Class that defines data for the event
//
public class AlarmEventArgs : EventArgs {   
    private int nrings = 0;
    // Constructor.
    public AlarmEventArgs(int nrings) {
	this.nrings = nrings;
    }

    // Properties.
    public int NumRings { 
	get { return nrings; }
    }
}
   
//Step 2. Delegate declaration.
//
public delegate void AlarmEventHandler(object sender, AlarmEventArgs e);

// Class definition.
//
public class AlarmClock {
    //Step 3. The Alarm event is defined using the event keyword.
    //The type of Alarm is AlarmEventHandler.
    public event AlarmEventHandler Alarm;

    //
    //Step 4. The protected OnAlarm method raises the event by invoking 
    //the delegates. The sender is always this, the current instance of 
    //the class.
    //   
    protected virtual void OnAlarm(AlarmEventArgs e) 
    {
	if (Alarm != null) {
	    //Invokes the delegates.
	    Alarm(this, e); 
	}
    }

    public void ForceAlarm() {
	OnAlarm(new AlarmEventArgs(3));
    }
}

public class Test {
    static public void Main() {
	new Test();
    }

    public Test() {
	AlarmClock clock = new AlarmClock();
	clock.Alarm += new AlarmEventHandler(alarmHandler);

	clock.ForceAlarm();
    }

    void alarmHandler(object sender, AlarmEventArgs e) {
	Console.WriteLine("alarm!  " + e.NumRings + " rings");
    }
}

Source in alarm-clock.cs