Java-Swing: Ereignisse und ihre Listener
Willemers Informatik-Ecke
Grafikprogrammierung Swing-Timer und Animation

Eine grafische Applikation wird durch die Ereignisse gesteuert, die eintreten, wenn der Anwender mit dem Programm interagiert. Die Ereignisse werden von den Swing-Elementen zu einem großen Teil selbst behandelt. Beispielsweise drückt sich der Button scheinbar ein, wenn man daraufklickt.

Eine grafische Anwendung hat aber selbst auch Interesse an den Ereignissen. Beispielsweise möchte es auf Mausklicks selbst reagieren. Da eine entsprechende Klasse bereits JFrame oder JPanel erweitert, muss ein Interface implementiert werden, schon allein weil Java eine Mehrfachvererbung nicht zulässt.

Mausereignisse

Mausereignisse lassen sich sowohl von JFrame als auch von JPanel aus fangen. Da ein JPanel aber keinen Rand hat, sind die Positionen viel einfacher zu lokalisieren.

Im ersten Schritt sorgen wir dafür, dass ein JFrame ein JPanel aufnimmt.

import javax.swing.JFrame;

public class MeinFrame extends JFrame {
    public MeinFrame() {
        this.setSize(400, 300);
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.add(new MeinPanel());
    }

    public static void main(String[] args) {
        new MeinFrame();
    }
}
Da es die Klasse MeinPanel noch nicht gibt, können Sie unter Eclipse den Fehler anklicken und Eclipse bietet an, die Klasse selbst zu erzeugen. Ansonsten müssen Sie das von Hand erledigen.

Die Klasse MeinPanel soll die Klasse JPanel erweitern und damit es später die Mausklicks auswerten kann, soll es das Interface MouseListener implementieren. Es fehlen dann noch die Importe, die Sie unter Eclipse mit [Strg]+[Shift]+[O] automatisch einpflegen lassen können.

import javax.swing.JPanel;
import java.awt.event.MouseListener;

public class MeinPanel extends JPanel implements MouseListener {
Um Mausereignisse zu fangen, implementiert die Anwendung ...

MouseListener

Das Interface MouseListener erfordert die Implementierung der folgenden Methoden:

MouseMotionListener

Das Interface MouseListener erfordert die Implementierung der folgenden Methoden: Über das als Paramter übergebene Objekt der Klasse MouseEvent können die Methoden getX und getY aufgerufen werden, um die momentane Mausposition zu ermitteln.

Das MouseEvent

Alle Maus-Listener-Methoden erhalten als Parameter eine Referenz auf ein MouseEvent. MouseEvent liefert über folgende Methoden weitere Informationen:

Kleine Anwendung

Die folgende Anwendung erzeugt an den Punkt, an den man klickt, einen kleinen roten Punkt.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JPanel;

public class MeinPanel extends JPanel implements MouseListener {

    private int x, y;

    public MeinPanel() {
        this.addMouseListener(this);
    }
    
    @Override
    public void paint(Graphics gr) {
        super.paint(gr);
        gr.setColor(Color.red);
        gr.fillOval(x-1, y-1, 3, 3);
    }
    
    @Override
    public void mouseClicked(MouseEvent e) {
        x = e.getX();
        y = e.getY();
        this.repaint();
    }

    @Override
    public void mouseEntered(MouseEvent arg0) {}
    @Override
    public void mouseExited(MouseEvent arg0) {}
    @Override
    public void mousePressed(MouseEvent arg0) {}
    @Override
    public void mouseReleased(MouseEvent arg0) {}
}
Dazu wird folgende Frame-Klasse benötigt:
import javax.swing.JFrame;

public class MeinFrame extends JFrame {
    public MeinFrame() {
        this.setSize(400, 300);
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.add(new MeinPanel());
    }

    public static void main(String[] args) {
        new MeinFrame();
    }
}

Tastaturereignisse

Prinzipiell ist die Vorgehensweise beim Einsammeln der Tastenereignissen ähnlich wie bei den Mausereignissen. Ein Panel, das Tastenereignisse lesen will, sieht also etwa so aus:
import javax.swing.JPanel;
import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;

public class MeinPanel extends JPanel implements KeyListener {

    public MeinPanel() {
        this.addKeyListener(this);
        this.setFocusable(true);
    }

    @Override
    public void keyPressed(KeyEvent arg0) { }

    @Override
    public void keyReleased(KeyEvent arg0) { }

    @Override
    public void keyTyped(KeyEvent arg0) { }
}

Fensterereignisse

Schließkreuz führt zum Ende des Fensters

Das Schließen des Fensters führt bei Swing nicht zwingend zum Beenden der Applikation. Um dies doch zu erreichen, muss die JFrame-Methode setDefaultCloseOperation aufgerufen werden:
import javax.swing.JFrame;

public class MeinJFrame extends JFrame{
    public MeinJFrame() {
        // ...
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}

Spontanes Einbinden eines WindowListeners

Möchte das Programm vor dem Ende die Daten sichern oder andere Reinigungsarbeiten übernehmen, muss es das Ende-Ereignis fangen. Dazu fügt es einen neuen WindowAdapter als WindowListener hinzu, der die Methode windowClosing überschreibt.
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;

public class MeinFrame extends JFrame {
    public MeinFrame() {
        this.setSize(400, 300);
        this.setVisible(true);
        this.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent ev) {
                dispose();
                System.exit(0);
            }
        });

    }
}
Diese sehr kompakte Schreibweise ersetzt einen ordentlichen WindowListener.

Implementierung eines WindowListeners

WindowListener ist ein Interface, das von der eigenen JFrame-Klasse implementiert werden muss.
import javax.swing.JFrame;
import java.awt.event.WindowListener;
import java.awt.event.WindowEvent;

public class MeinFrame extends JFrame implements WindowListener {
    public MeinFrame() {
        this.setSize(400, 300);
        this.setVisible(true);
        this.addWindowListener(this);
    }
Natürlich müssen die passenden Importe aufgeführt werden. Aber vor allem muss sich der Konstruktor als WindowListener für das eigene Fenster anmelden. Dazu ruft er addWindowListener mit dem Parameter this auf.

Wer WindowListener implementiert, muss auf jeden Fall die folgenden Methoden implementieren:

@Override
public void windowActivated(WindowEvent e) { }

@Override
public void windowClosed(WindowEvent e) { }

@Override
public void windowClosing(WindowEvent e) { }

@Override
public void windowDeactivated(WindowEvent e) { }

@Override
public void windowDeiconified(WindowEvent e) { }

@Override
public void windowIconified(WindowEvent e) { }

@Override
public void windowOpened(WindowEvent e) { }
Nun muss die Methode windowsClosing das tun, was erforderlich ist, damit das Programm aufgeräumt verlassen werden kann.
    @Override
    public void windowClosing(WindowEvent e) {
        dispose();
        System.exit(0);
    }

Grafikprogrammierung Swing-Timer und Animation