Event-Interface und Event-Adapter

Die Implementierung eines einfachen ActionListener-Schnittstelle ist recht einfach, da nur eine Methode implementiert werden muss.

Viele nicht triviale ActionListener erfordern jedoch die Implementierung von mehreren Methoden aufgrund der Komplexität der entsprechenden Komponente. Ein Beispiel hierfür ist die Schnittstelle MouseListener. Sie erfordert die Implementierung der folgenden Methoden:

  • mouseClicked(MouseEvent e)
  • mouseEntered()
  • mouseExited()
  • mousePressed()
  • mouseReleased()

Dies ist aufwändig wenn man sich nur für ein bestimmtes Ereignis wie z. Bsp. mouseReleased() interessiert. Man muss alle Interfacemethoden implementieren. Vier der Methoden bleiben leer und sind überflüssig.

Listener-Adapter Klassen

Um diese unnötige Schreibarbeit zu vermeiden, stellt Swing nach dem Entwurfsmuster Adapter Klassen als abstrakte Klassen mit leeren, aber schon implementierten Methoden zur Verfügung.

Vorteil: Der Entwickler kann seine Klasse aus der abstrakten Klasse ableiten und muss nur die Methoden für die Ereignisse implementieren die ihn interessieren.

Für die Implementierung von Maus-Events steht zum Beispiel die Klasse MouseAdapter zur Verfügung, die die entsprechenden Methoden implementiert.

Einige der Adapterklassen die Swing zur vereinfachten Implementierung von Ereignisschnittstellen (Event Interface) sind:

Beispiele von Adapterklassen
Spezialisierungen der Schnittsteller EventListener Adapterklasse
ComponentListener ComponentAdapter
ContainerListener ContainerAdapter
FocusListener FocusAdapter
KeyListener KeyAdapter
MouseListener MouseAdapter
MouseMotionListener MouseMotionAdapter
WindowListener WindowAdapter

Im folgenden Beispiel wird die Klasse MouseAdapterTest aus der abstrakten Klasse MouseAdapter abgeleitet um nur die Methode mouseClicked() implementieren zu müssen:

package s2.swing;

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JFrame;

public class MouseAdapterTest extends MouseAdapter {

   public MouseAdapterTest() {
      erzeugeGUI();
   }

   public static void main(String[] args) {
      MouseAdapterTest mat = new MouseAdapterTest();
   }

   private void erzeugeGUI() {
      JFrame myJFrame = new JFrame("Mouse Click Adapter Test");
      myJFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      JButton jb = new JButton("Hier drücken");
      jb.addMouseListener(this);
      myJFrame.getContentPane().add(jb);
      myJFrame.pack();
      myJFrame.setVisible(true);
   }

   @Override
   public void mouseClicked(MouseEvent mEvent) {
      System.out.println("MouseClick wurde auf Position ["
         + mEvent.getX() + ","
         + mEvent.getY() + "] "
         + mEvent.getClickCount() + " mal geklickt");
  }
} // Ende der Klasse

Das Programm registriert sich selbst gegen den Button und ist jetzt in der Lage, die Information des dEventobjekts mEvent auszulesen (x,y Position, Anzahl der Mehrfachclicks).

Beispiel

Im Diagramm (unten) sind die beiden Möglichkeiten aufgeführt die ein Entwickler zum Auslesen eines Mauscklicks benutzen kann. Die von Java zur Verfügung gestellten Infrastruktur besteht aus dem zu implementierenden Interface MouseListener und einer abstrakten Klasse Mouseadapter:

Ein Entwickler der sich nur gegen das MouseClick Ereignis registrieren möchte, kann wie im Diagramm oben:

  • das Interface MouseListener in z.Bsp. der Klasse ListenerAufwaendig implementieren. Hier müssen alle 5 Methoden des Interface implementiert werden. Die vier nicht benötigten Methoden können als leere Methoden implementiert werden.
  • aus der abstrakten Klasse MouseAdapter eine Klasse wie z.Bsp. ListenerEinfach ableiten. In ihr muss man nur eine einzige Methode mouseClicked() durch Überschreiben implementieren. Die anderen vier Methoden sind schon in der Klasse MouseAdapter als leere Proformamethoden implementiert. Beim Ableiten aus der abstrakten Klasse MouseAdapter müssen nur die gewünschten Methoden überschrieben werden. Ein Konstruktor ist nicht nötig, da die Klasse MouseAdapter einen Default-Konstruktor besitzt.

Anbei die vollständige Implementierung der semantisch gleichwertigen Methoden:

Vergleich
Klasse ListenerAufwaendig Klasse ListenerEinfach
package s2.swing;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
 
public class ListenerAufwaendig implements MouseListener{
    @Override public void mouseClicked(MouseEvent mEvent) {
        System.out.println("MouseClick wurde auf Position ["
                + mEvent.getX() + ","
                + mEvent.getY() + "] "
                + mEvent.getClickCount() + " mal geklickt");
    }
    @Override public void mouseEntered(MouseEvent mEvent) 
        { /* leere Implementierung, erzwungen */ }
    @Override public void mouseExited(MouseEvent mEvent) 
        { /* leere Implementierung, erzwungen */ }
    @Override public void mousePressed(MouseEvent mEvent)
        { /* leere Implementierung, erzwungen */ }
    @Override public void mouseReleased(MouseEvent mEvent)
     { /* leere Implementierung, erzwungen */ }
}
package s2.swing;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
 
public class ListenerEinfach extends MouseAdapter{
    @Override public void mouseClicked(MouseEvent mEvent) {
        System.out.println("MouseClick wurde auf Position ["
                + mEvent.getX() + ","
                + mEvent.getY() + "] "
                + mEvent.getClickCount() + " mal geklickt");
    }
}