(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 | Beschreibung |
---|---|---|
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. 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
}
}