(Basis der Erläuterungen: Java ist auch eine Insel (8. Auflage))

Im Ereignismodell von Java gibt es eine Reihe von Ereignisauslösern (Ereignisquellen, engl. event source), wie zum Beispiel Schaltflächen. Die Ereignisse können von der grafischen Oberfläche kommen, etwa wenn der Benutzer eine Schaltfläche anklickt, aber auch auf eigene Auslöser zurückzuführen sein. Es gibt eine Reihe von Interessenten, die gern informiert werden wollen, wenn ein Ereignis aufgetreten ist. Da der Interessent in der Regel nicht an allen ausgelösten Oberflächen-Ereignissen interessiert ist, sagt er einfach, welche Ereignisse er empfangen möchte. Dies funktioniert so, dass er sich bei einer Ereignisquelle anmeldet, und diese informiert ihn, wenn sie ein Ereignis aussendet. [Das ist so, als ob ich einer Freund, den ich gerade kennengelernt habe, meine Telefonnummer hinterlasse. Anstatt ihn ewig anzurufen, warte ich. Wenn er Interesse hat, wird er sich melden.] Auf diese Weise leidet die Systemeffizienz nicht, da nur diejenigen informiert werden, die auch Verwendung für das Ereignis haben.

Da der Interessent an der Quelle horcht, heißt er auch Listener oder Horcher. Für jedes Ereignis gibt es einen eigenen Listener. Die folgende Tabelle gibt eine Übersicht über einige Listener und was sie für Ereignisse melden:

ListenerEreignisse
ActionListenerDer Benutzer aktiviert eine Schaltfläche bzw. ein Menü oder drückt Return auf einem Textfeld.
WindowListenerDer Benutzer schließt ein Fenster oder möchte es verkleinern.
MouseListenerDruck auf einen Mausknopf
MouseMotionListenerBewegung der Maus

Dem Listener übergibt das Grafiksystem jeweils ein Ereignis-Objekt, also dem ActionListener ein ActionEvent-Objekt, dem WindowListener ein WindowEvent-Objekt usw. Die Einzigen, die etwas aus der Reihe tanzen, sind MouseListener und MouseMotionListener, denn beide melden MouseEvent-Objekte.

ActionListener implementieren

Wird z. B. ein Button oder ein anderes Element betätigt, wird ein Actionevent ausgelöst, welches mit Hilfe des ActionListener ausgewertet werden kann. Die Implementation eines solchen ActionListener (im Java-Editor) ist relativ einfach, da hier alle notwendigen Quelltextfragmente automatisch erstellt werden. Schauen wir uns ein Beispiel an, in dem auf einem JFrame ein JButton platziert wird. Ohne weitere (händische) Änderungen wurde folgender Code generiert:

import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 import javax.swing.event.*;
 
 public class BspButton extends JFrame {
   // Anfang Attribute
   private JButton jButton1 = new JButton();
   
   // Ende Attribute
 
   public BspButton(String title) {
     // Frame-Initialisierung
     super(title);
     setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
     int frameWidth = 300;
     int frameHeight = 300;
     setSize(frameWidth, frameHeight);
     Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
     int x = (d.width - getSize().width) / 2;
     int y = (d.height - getSize().height) / 2;
     setLocation(x, y);
     Container cp = getContentPane();
     cp.setLayout(null);
     // Anfang Komponenten
 
     jButton1.setBounds(96, 104, 75, 25);
     jButton1.setText("jButton1");
     jButton1.addActionListener(new ActionListener() {
       public void actionPerformed(ActionEvent evt) {
         jButton1_ActionPerformed(evt);
       }
     });
     cp.add(jButton1);
     // Ende Komponenten
 
     setResizable(false);
     setVisible(true);
   }
 
   // Anfang Methoden
   public void jButton1_ActionPerformed(ActionEvent evt) {
     // TODO hier Quelltext einfügen
   }
 
   // Ende Methoden
 
   public static void main(String[] args) {
     new BspButton("BspButton");
   }
 }

In der Methode public void jButton1_ActionPerformed(ActionEvent evt) können sofort die gewünschten Aktionen programmiert werden.

MouseListener und MouseMotionListener implementieren

MouseListener und MouseMotionListener erfassen mögliche auftretende Mausereignisse:

ListenerEreignisseBeschreibung
MouseListenermousePressedWird aufgerufen, wenn die Maustaste gedrückt wurde.
mouseReleasedWird aufgerufen, wenn die Maustaste losgelassen wurde.
mouseClickedWird aufgerufen, wenn Sie die Maustaste geklickt wurde (kompletter Klick).
mouseEnteredWird aufgerufen, wenn die Maus eine Komponente betritt.
mouseExitedWird aufgerufen, wenn die Maus eine Komponente verlässt.
MouseMotionListenermouseMovedWird aufgerufen, wenn sich die Maus über ein Element bewegt.
mouseDraggedWird aufgerufen, wenn sich Maus gedrückt über ein Element bewegt.

Je nachdem, welche Mausereignisse benötigt werden, müssen die entsprechenden Listener implementiert werden. Eine Möglichkeit ist, diese bei der Klassendefinition zu implementieren. (Eine zweite Möglichkeit ist die Verwendung von Adapterklassen – diese Variante soll an dieser Stelle nicht weiter verfolgt werden.).

Beispiel

Auf einem JPanel (als Objekt in einem JFrame) soll die Farbe per Mausklick einstellbar sein (linke Maustaste – rot, rechte Maustaste – blau). Zudem soll die Position des Mauszeigers angezeigt werden. Das hier besprochene Beispiel läuft im JavaEditor, in anderen Entwicklungsumgebungen könnten Anpassungen notwendig sein.

Bewegt sich die Maus über das JPanel, wird ein mouseMoved-Event ausgelöst, daher benötigen wir den MouseMotionListener. Ein Mausklick kann als mousePressed-, mouseReleased- oder mouseClicked-Event verarbeitet werden, d. h. wir benötigen auch den MouseListener. Beide Listener müssen also implementiert werden:

public class BspMaus extends JFrame implements MouseListener, MouseMotionListener {
 
   // Anfang Attribute
   private JPanel zeichenflaeche = new JPanel();
   private JLabel mausPosLabel = new JLabel();
   // Ende Attribute

Das JPanel, auf dem die Mausaktionen durchgeführt werden sollen heißt zeichenflaeche, zusätzlich gibt es noch ein JLabel, in welchem die Position der Maus angezeigt werden soll.

Bei der Initialisierung der einzelnen Komponenten müssen nun (neben den automatisch generierten Codezeilen) die gewünschten Listener eingebunden werden, in diesem Fall für das Objekt zeichenflaeche:

    // Anfang Komponenten
    zeichenflaeche.setBounds(7, 2, 500, 190);
    zeichenflaeche.setBackground(Color.WHITE);
    zeichenflaeche.addMouseMotionListener(this);
    zeichenflaeche.addMouseListener(this);
    cp.add(zeichenflaeche);
    ...
  }

Da wir die beiden Listener direkt in der Klasse BspMaus einbinden, müssen alle entsprechenden Methoden zur Behandlung der einzelnen Ereignisse überschrieben werden:

  // Anfang Methoden
  /*
   * MouseListener - Ereignisroutinen
   */
  public void mouseExited(MouseEvent e) {
  }
 
  public void mousePressed(MouseEvent e) {
  }
 
  public void mouseEntered(MouseEvent e) {
  }
 
  public void mouseReleased(MouseEvent e) {
  }
 
  public void mouseClicked(MouseEvent e) {
  }
 
  /*
   * MouseMotionListener - Ereignisroutinen
   */
  public void mouseMoved(MouseEvent e) {
  }
 
  public void mouseDragged(MouseEvent e) {
  }

Jetzt kann der notwendige Quelltext in den jeweiligen Methoden implementiert werden. Die Bewegung der Maus über dem Objekt zeichenflaeche löst ein Event aus, welches die Methode mouseMoved aufruft. Die jeweilige Mausposition (über der Zeichenfläche) kann folgendermaßen ausgelesen werden:

  public void mouseMoved(MouseEvent e) {
    int ex = e.getX();     // Auslesen der x-Koordinate
    int ey = e.getY();     // Auslesen der y-Koordinate
 
    if (e.getSource() == zeichenflaeche) {     // Wurde das Event von zeichenflaeche ausgelöst?
      mausPosLabel.setText("Mouseposition: (" + ex + "|" + ey + ")");     // Werte ausgeben
    }
  }

Ein Mausklick auf zeichenflaeche kann (für unser Problem) von verschiedenen Methoden bearbeitet werden. Soll reagiert werden, wenn die Maustaste gedrückt wird (mausPressed), die Maustaste losgelassen wird (mausReleased) oder ein kompletter Klick stattgefunden hat (mausClicked). Möglich wäre z. B. dieser Code:

  public void mousePressed(MouseEvent e) {
 
    if (!e.isMetaDown()) {     // wurde linke Maustaste gedrückt?
      zeichenflaeche.setBackground(Color.RED);     // Hintergrund rot setzen
    } else {
      zeichenflaeche.setBackground(Color.BLUE);     // Hintergrund blau setzen
    }
  }

Schlagwörter: