Wie kann auf Ereignisse reagiert werden?

Aus Informatik
Wechseln zu: Navigation, Suche

(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:

Listener Ereignisse
ActionListener Der Benutzer aktiviert eine Schaltfläche bzw. ein Menü oder drückt Return auf einem Textfeld.
WindowListener Der Benutzer schließt ein Fenster oder möchte es verkleinern.
MouseListener Druck auf einen Mausknopf
MouseMotionListener Bewegung 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:

Listener Ereignisse
MouseListener mousePressed Wird aufgerufen, wenn die Maustaste gedrückt wurde.
mouseReleased Wird aufgerufen, wenn die Maustaste losgelassen wurde.
mouseClicked Wird aufgerufen, wenn Sie die Maustaste geklickt wurde (kompletter Klick).
mouseEntered Wird aufgerufen, wenn die Maus eine Komponente betritt.
mouseExited Wird aufgerufen, wenn die Maus eine Komponente verlässt.
MouseMotionListener mouseMoved Wird aufgerufen, wenn sich die Maus über ein Element bewegt.
mouseDragged Wird 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.

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
    }
  }