Event handling

Event Handling

Java’s event handling is based on delegation: the source delegates event handling to listener. To do this, 3 things are necessary:

  1. the component or source triggering an event
  2. the event self containing info about the event
  3. the handler which implements the processing of the event

Regarding 2: Java knows a bunch of event classes that can be created by different sources as e.g. Swing components. The root class EventObject has a method getSource() with which the source of the event can be retained. The EventObject class is a direct subclass of object and belongs to the java.util package. This means, that, although most people might know Event classes from the graphical AWT package, its functionality is much more generic and not restricted to the use of graphical events.

Not every java class can be a source for a (specific subclass of) EventObject. A class explicitly needs to support a certain event. If this is the case, we can conclude several things:

Prerequisite: - class B supports XEvent

Consequence - there exists an interface XListener - for Listeners with more than one method there is also an abstract XAdapter class implementing the XListener interface - class B has a method with signature public void addXListener(XListener l)

How to implement event handling

To implement event handlering one has to follow these steps - Define a Listener class, which is a class that implements a specific listener interface (E.g. for responses to Mouse behavior define a class implementing the MouseListener) - Implement within the Listener class the procedure or behavior that should be elicited by the Event class (e.g. To respond to the mouse hovering above a certain Component of a gui, add logic to the mouseEntered-method) - Register an instance of the Listener class by adding the listener to the component (e.g. add the new Listener Class instance to the JLabel label)


// Step 1.) The Java class MyListener implementing the Listener interface
public class MyListener implements MouseListener {
    public void mousePressed(MouseEvent e) {}
    public void mouseReleased(MouseEvent e) {}
    public void mouseClicked(MouseEvent e) {}
    // Step 2.) Implementation of the specific behavior following the event
    public void mouseEntered(MouseEvent e) {((JLabel)e.getSource()).setBackground(Color.RED);}
    public void mouseExited(MouseEvent e) {((JLabel)e.getSource()).setBackground(Color.LIGHT_GRAY);}
}
// Step 3.) Coupling of the source of the event and the Listener class
label.addMouseListener(new MyListener()); // component in in MyFrame

Adapter classes

EventListener interfaces with more than one method also have a Adapter class. This abstract class implements all interface methods with an empty body. So, to save some type work you can implement a class inheriting from that adapter class and only overwrite the method you are going to use and leave out all unused methods.

public class MyListener extends MouseAdapter {
    @Override
    public void mouseEntered(MouseEvent e) {((JLabel)e.getSource()).setBackground(Color.RED);}
    @Override
    public void mouseExited(MouseEvent e) {((JLabel)e.getSource()).setBackground(Color.LIGHT_GRAY);}
}

Where to define the listener class

There are several option how to define a listener class

  • Create completely new class outside the class eliciting the event (disadvantage: the listener class has only info about triggering component, thus can only alter behavior of the source. But there might be other classes in the class where the source is located.)
  • Create inner class (use qualified this to acces attributes of outer class)
  • Create local class within method (without accessibility specs)
  • Create anonymous class (same as local class but shorter)
  • Let JFrame-class implement the interface
// Example anonymous local class
label.addMouseListener(new MouseAdapter() {
      public void mouseEntered(MouseEvent e) {/** your implementation**/}     
      public void mouseExited(MouseEvent e) {/** your implementation**/}
    });   

Difference between different EventListeners

There are differences between different types of listeners. An ActionListener will elicit one event, ChangeListener can elicit several events. Events can be elicited before a user does anything.

box.addItemListener(new ItemListener () {
      @Override
      public void itemStateChanged(ItemEvent e) {
        if (e.getStateChange() == ItemEvent.SELECTED) {
          JComboBox choice = (JComboBox)e.getSource();
          System.out.println(choice.getSelectedItem().toString());
        }
      }
      });

Event handling Threads

In order to put the desired functionality of interclass interactivity into effect, Java has 2 threads: the PostEventQueue and the EventDispatcher. PostEventQueue listens to events of the OS and sends these as new events to the dispatcher. The Event dispatcher looks whether there are new events on the stack and processes them serially.

Thread-safe event handling

Swing components are not thread safe. If there are more threads than one that alter e.g. the content of a certain field java can not guarantee the timing of the processing of the threads. In order to program a gui thread safe one needs to send all events to the event dispatcher. By using this thread, java can guarantee that all instructions are sequentially processed.

For regular changes of gui components by non-user events one can utilize the Timer class. This class can be instantiated with two parameters, the delay for creating an ActionEvent and register the Listener which will be triggered after each delay.

private Timer timer = new Timer(1000, new TimerListener());
timer.start();

public class TimerListener implements ActionListener{
  public void actionPerformed(ActionEvent e){
    // place logic here
  }
}
}