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 ...
- das Interface MouseListener für einmalige Ereignisse wie das Klicken
- oder MouseMotionListener, um über Bewegungen der Maus informiert zu werden.
- Das Interface MouseInputListener vereinigt beides in sich.
MouseListener
Das Interface MouseListener erfordert die Implementierung der folgenden Methoden:- void mouseClicked(MouseEvent e)
Die Methode mouseClicked wird aufgerufen, wenn ein vollständiger Klick ausgeführt wurde. Ein Klick besteht aus dem Herunterdrücken und dem Loslassen der Maustaste. Diese beiden Ereignisse lassen sich auch separat bearbeiten. - void mousePressed(MouseEvent e)
Die Methode mousePressed wird aufgerufen, wenn die Maustaste gedrückt wird und mouseReleased, wenn sie wieder losgelassen wird. - void mousePressed(MouseEvent e)
Tatsächlich wird in der Praxis meist mouseReleased verwendet, wenn ein Mausklick behandelt werden soll.
MouseMotionListener
Das Interface MouseListener erfordert die Implementierung der folgenden Methoden:- void mouseMoved(MouseEvent ev)
Diese Methode muss auf jeden Fall implementiert werden. Sie wird bei Mausbewegungen aufgerufen. - void mouseDragged(MouseEvent ev)
Diese Methode wird aufgerufen, wenn die Maus bei gedrückter Taste bewegt wird.
Das MouseEvent
Alle Maus-Listener-Methoden erhalten als Parameter eine Referenz auf ein MouseEvent. MouseEvent liefert über folgende Methoden weitere Informationen:- int getX(): die X-Position der Maus in diesem Panel
- int getY(): die Y-Position der Maus in diesem Panel
- int getClickCount(): die Anzahl der Klicks
- int getButton(): welcher Button wurde gedrückt
Ergebnis wird mit MouseEvent.BUTTON1 bis MouseEvent.BUTTON3 verglichen. - boolean isShiftDown(): ist die Shift-Taste gedrückt?
- boolean isAltDown(): ist die Alt-Taste gedrückt?
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.- Die Klasse implementiert KeyListener.
- Im Konstruktor meldet sich die Klasse durch Aufruf von addKeyListener an.
this.addKeyListener(this);
- Außerdem muss das Panel auch fokussierbar sein. Das erfolgt über den
Aufruf von setFocusable:
this.setFocusable(true);
- Nun implementiert die Klasse die Methoden keyTyped, keyPressed und
keyReleased und wird so darüber informiert, wenn der Anwender eine
Taste drückt.
void keyTyped(KeyEvent ke) void keyPressed(KeyEvent ke) void keyReleased(KeyEvent ke)
- Aus dem übergebenen Objekt der Klasse KeyEvent können die Tasten
ermittelt werden.
- getKeyChar ermittelt die Taste als char
- getKeyCode gibt den Unicode zurück. Diese wird auch für das Fangen
der Sondertasten verwendet. Hier die Cursortasten:
switch (ke.getKeyCode()) { case KeyEvent.VK_UP: ... break; case KeyEvent.VK_DOWN: ... break; case KeyEvent.VK_LEFT: ... break; case KeyEvent.VK_RIGHT: ... break; }
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 |