Ereignisverarbeitung
Bisher sehen unsere grafischen Oberflächen zwar schön aus, sind aber noch ohne
praktischen Nutzen, da wir noch keine Ereignisverarbeitung realisiert haben.
Der Mechanismus der Ereignisverarbeitung in Java lässt sich sehr gut mit
entsprechenden Vorgängen in der realen Welt vergleichen. Nehmen wir zum
Beispiel eine Trommel als Quelle eines Ereignisses, so können wir durch einen
Schlag auf die Trommel mit dem Schlägel ein Ereignis auslösen, das von einem
Empfänger (einem Zuhörer) vernommen werden kann. In Java versteht man unter
einem Ereignis (event) etwas, das die Benutzerin bzw. der
Benutzer beim Arbeiten mit der grafischen Oberfläche auslösen kann, indem sie
bzw. er beispielsweise die Maus bewegt, eine Schaltfläche drückt, einen
Menü-Eintrag auswählt oder eine Taste betätigt. Innerhalb eines Java-Programms
werden solche Ereignisse als Objekte von Ereignis-Klassen dargestellt. Erzeugt
werden diese Objekte von den so genannten Ereignisquellen (event
sources), die entsprechende Ereignisse auslösen können. Jede Komponente
einer grafischen Oberfläche (z.B. ein Button, auf den gerade gedrückt wird)
kann eine solche Ereignisquelle sein.
Die Gegenstücke zu den Ereignisquellen bilden die so genannten Ereignisempfänger
(event listener). Dabei handelt es sich um Objekte, die quasi als
"Aufpasser" oder "Lauscher" dienen können. Damit ein solches Empfänger-Objekt
auch tatsächlich Ereignisse von einer Ereignisquelle empfangen kann, muss es
nach seiner Erzeugung bei der entsprechenden Ereignisquelle registriert werden.
Einfaches Beispiel: Eine Ereignisquelle
In diesem Beispiel sezten wir das Konzept der Ereignisverarbeitung in Java an
einem sehr einfachen Beispiel um: Die grafische Oberfläche besteht nur aus
einem Button. Ein Klick auf diesen Button soll die Hintergrundfarbe unseres
Containers ändern. Bevor wir die Ereignisverarbeitung einbauen, sieht unsere
GUI-Klasse folgendermaßen aus:
import javax.swing.*;
import java.awt.*;
public class Farbwechsel extends JFrame {
Container c;
JButton button;
public Farbwechsel(){
// Container bestimmen
c = getContentPane();
// Button erzeugen und dem Container hinzufügen
button = new JButton("Hintergrundfarbe wechseln");
c.add(button, BorderLayout.NORTH);
}
public static void main(String[] args){
Farbwechsel fenster = new Farbwechsel();
fenster.setTitle("Farbwechsel");
fenster.setSize(200,100);
fenster.setVisible(true);
fenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Zunächst kümmern wir uns um unseren Ereignisempfänger (Listener-Objekt). Dazu
müssen wir zunächst wissen, auf welche Art von Event unser Listener ansprechen
soll. Im Falle eines gedrückten Buttons handelt es sich um ein Action-Event
(ein Objekt der Klasse ActionEvent). Nun gilt es also eine Klasse zu
schreiben, deren Objekte wissen, was beim Empfang eines Action-Ereignisses zu
tun ist.
Um dies zu gewährleisten, müssen wir uns beim Programmieren an bestimmte
Regeln halten, die in einem Interface festgelegt sind. Für Action-Ereignisse
zuständig ist das Interface ActionListener, das somit von unserer
Listener-Klasse implementiert werden muss. Das Interface ActionListener zwingt
uns die Methode actionPerformed zu implementieren. Diese Methode wird
aufgerufen, sobald unser Listener-Objekt ein Action-Event empfängt.
class ButtonListener implements ActionListener{
public void actionPerformed(ActionEvent e){
// Hintergrundfarbe des Containers zufällig ändern
float zufall = (float) Math.random();
Color grauton = new Color(zufall, zufall, zufall);
c.setBackground(grauton);
}
}
In der Methode actionPerformed sorgen wir dafür, dass sich die
Hintergrundfarbe des Containers ändert. Realisiert man die Klasse
ButtonListener nun als eigene Klasse hat man nun das Problem, dass man auf die
Container-Variable c keinen Zugriff hat. Eine Lösungsmöglichkeit besteht
darin, die Klasse ButtonListener als innere Klasse innerhalb der Klasse
Farbwechsel zu implementieren.
Unter Verwendung der Klasse ButtonListener sind wir nun in der Lage, mit
ButtonListener bL = new ButtonListener();
button.addActionListener(bL);
das Empfänger-Objekt zu erzeugen und bei der Eventquelle zu registrieren. Die
dabei eingesetzte Methode addActionListener wird in der Klasse JButton
bereitgestellt und erwartet einen Parameter vom Typ ActionListener, d.h. ein
Objekt einer Klasse, die das Action-Listener-Interface implementiert hat.
Insgesamt hat das Programm folgende Gestalt:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Farbwechsel extends JFrame {
Container c;
JButton button;
public Farbwechsel(){
// Container bestimmen
c = getContentPane();
// Button erzeugen und dem Container hinzufügen
button = new JButton("Hintergrundfarbe wechseln");
c.add(button, BorderLayout.NORTH);
// Listener-Objekt erzeugen und beim Button registrieren
ButtonListener bL = new ButtonListener();
button.addActionListener(bL);
}
// Innere Button-Listener Klasse
class ButtonListener implements ActionListener{
public void actionPerformed(ActionEvent e){
float zufall = (float) Math.random();
Color grauton = new Color(zufall, zufall, zufall);
c.setBackground(grauton); // Zugriff auf c möglich
}
}
public static void main(String[] args){
Farbwechsel fenster = new Farbwechsel();
fenster.setTitle("Farbwechsel");
fenster.setSize(200,100);
fenster.setVisible(true);
fenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Zweites Beispiel: Mehrere Ereignisquellen
Sobald die grafische Oberfläche aus mehreren Komponenten besteht, die in der
Lage sind, dieselben Events zu erzeugen, stellt sich die Frage, wie man die
Ereignisquelle eines Events identifizieren kann. Im Falle von ActionEvents
lassen sich dafür die Methoden addActionCommand und getActionCommand verwenden.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Bilderrahmen extends JFrame {
Container c;
JMenuBar menuBar;
JMenu menu;
JMenuItem menuItem1, menuItem2, menuItem3;
JButton button1, button2, button3;
JToolBar toolBar;
JLabel bildLabel;
public Bilderrahmen(){
c = getContentPane();
//Erzeuge das Listener-Objekt für das Menü
MenuListener mL = new MenuListener();
// Erzeuge die Menüleiste
menuBar = new JMenuBar();
// Erzeuge ein Menü
menu = new JMenu("Bilder");
// Erzeuge die Menüeinträge und füge sie dem menü hinzu
menuItem1 = new JMenuItem("Music");
menuItem1.addActionListener(mL);
menu.add(menuItem1);
menuItem2 = new JMenuItem("Like a Virgin");
menuItem2.addActionListener(mL);
menu.add(menuItem2);
menuItem3 = new JMenuItem("True Blue");
menuItem3.addActionListener(mL);
menu.add(menuItem3);
// Füge das Menü der Menüleiste hinzu
menuBar.add(menu);
// Fügt die Menüleiste dem Frame hinzu
setJMenuBar(menuBar);
// Erzeuge das Listener-Objekt für die Werkzeugleiste
ToolBarListener tL = new ToolBarListener();
// Erzeuge die Werkzeugleiste
toolBar = new JToolBar("Rahmenfarbe");
// Erzeuge Buttons
button1 = new JButton("Schwarz");
button1.addActionListener(tL);
toolBar.add(button1);
button2 = new JButton("Grau");
button2.addActionListener(tL);
toolBar.add(button2);
button3 = new JButton("Weiss");
button3.addActionListener(tL);
toolBar.add(button3);
// Erzeuge das Label mit Initial-Bild
bildLabel = new JLabel(new
ImageIcon("images/music.jpg"));
// Setze die Hintergrundfarbe des Containers
c.setBackground(Color.LIGHT_GRAY);
// Füge das Label dem Container hinzu
c.add(bildLabel, BorderLayout.CENTER);
c.add(toolBar, BorderLayout.NORTH);
}
class MenuListener implements ActionListener{
public void actionPerformed(ActionEvent e){
// Bildauswahl abhängig von der Aktion
if(e.getSource() == menuItem1)
bildLabel.setIcon(new ImageIcon("images/music.jpg"));
else if(e.getSource() == menuItem2)
bildLabel.setIcon(new
ImageIcon("images/like_a_virgin.jpg"));
else if(e.getSource() == menuItem3)
bildLabel.setIcon(new
ImageIcon("images/true_blue.jpg"));
}
}
class ToolBarListener implements ActionListener{
public void actionPerformed(ActionEvent e){
// Bildauswahl abhängig von der Aktion
if(e.getSource() == button1)
c.setBackground(Color.BLACK);
else if(e.getSource() == button2)
c.setBackground(Color.LIGHT_GRAY);
else if(e.getSource() == button3)
c.setBackground(Color.WHITE);
}
}
public static void main(String[] args){
Bilderrahmen fenster = new Bilderrahmen();
fenster.setTitle("Bilderrahmen");
fenster.setSize(360,440);
fenster.setVisible(true);
fenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Programmiervarianten für die Ereignisverarbeitung
Wie oben bereits erwähnt, gibt es verschiedene Möglichkeiten, das in Java
verwendete Modell der Ereignisverarbeitung programmtechnisch umzusetzen. Man
kann dabei prinzipiell vier Varianten unterscheiden:
-
Die Listener-Klasse wird als innere Klasse realisiert (wie in den bereits
betrachteten Beispielen)
-
Die Listener-Klasse wird als anonyme Klasse realisiert
-
Die Container-Klasse wird selbst zur Listener-Klasse
-
Die Listener-Klasse wird als separater Klasse realisiert
Die Varianten 3 und 4 wollen wir am Beipsiel unserer Klasse Farbwechsel näher
erläutern.
Container-Klasse als Listener-Klasse
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/** Farbwechsel-Klasse selbst als Listener */
public class Farbwechsel extends JFrame implements
ActionListener{
Container c;
JButton button;
public Farbwechsel(){
// Container bestimmen
c = getContentPane();
// Button erzeugen und dem Container hinzufügen
button = new JButton("Hintergrundfarbe wechseln");
c.add(button, BorderLayout.NORTH);
// Eigenes Objekt beim Button als Listener registrieren
button.addActionListener(this);
}
public void actionPerformed(ActionEvent e){
float zufall = (float) Math.random();
Color grauton = new Color(zufall, zufall, zufall);
c.setBackground(grauton); // Zugriff auf c möglich
}
public static void main(String[] args){
Farbwechsel fenster = new Farbwechsel();
fenster.setTitle("Farbwechsel");
fenster.setSize(200,100);
fenster.setVisible(true);
fenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Listener-Klasse als separate Klasse
import java.awt.*;
import java.awt.event.*;
/** Eigenständige Listener-Klasse */
class ButtonListener implements ActionListener{
Container c; // Referenz auf den zu beeinflussenden
Container
public ButtonListener(Container c){
this.c = c; // Referenz auf den zu beeinflussenden
Container sichern
}
public void actionPerformed(ActionEvent e){
// Hintergrundfarbe des Containers zufällig ändern
float zufall = (float) Math.random();
Color grauton = new Color(zufall, zufall, zufall);
c.setBackground(grauton);
}
}
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/** Farbwechsel-Klasse mit separater Listener-Klasse */
public class Farbwechsel extends JFrame implements
ActionListener{
Container c;
JButton button;
public Farbwechsel(){
// Container bestimmen
c = getContentPane();
// Button erzeugen und dem Container hinzufügen
button = new JButton("Hintergrundfarbe wechseln");
c.add(button, BorderLayout.NORTH);
// Eigenes Objekt beim Button als Listener registrieren
button.addActionListener(c);
}
public static void main(String[] args){
Farbwechsel fenster = new Farbwechsel();
fenster.setTitle("Farbwechsel");
fenster.setSize(200,100);
fenster.setVisible(true);
fenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Drittes Beispiel: Euro-Rechner
import javax.swing.*; import java.awt.event.*;
public class EuroRechner extends JPanel{
JTextField tf_euro, tf_sonst; JComboBox cb_auswahl;
public EuroRechner(){ // Layout für unser Custom-JPanel festlegen setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); // Komponenten der Oberfläche erzeugen tf_euro = new JTextField(20); tf_sonst = new JTextField(20); cb_auswahl = new JComboBox(); // Komponenten dem Custom-JPanel hinzufügen add(tf_euro); add(cb_auswahl); add(tf_sonst); // Auswahlliste mit Währungsnamen füllen for(int i=0; i<12; i++){ cb_auswahl.addItem(EuroConverter.getBezeichnung(i)); } // Listener-Objekt erzeugen MyListener ml = new MyListener();
// und sowohl bei den Textfeldern tf_euro.addActionListener(ml); tf_sonst.addActionListener(ml); // als auch bei der JComboBox registrieren cb_auswahl.addActionListener(ml); } public class MyListener implements ActionListener {
double euro, sonst; public void actionPerformed(ActionEvent e) { // falls das Euro-Textfeld oder die Auswahlliste Auslöser des ActionEvents waren... if(e.getSource() == tf_euro || e.getSource() == cb_auswahl){
// wir müssen von String nach double casten, euro = Double.parseDouble(tf_euro.getText()); // weil convertToEuro als erstes Argument ein double-Wert erwartet. sonst = EuroConverter.convertFromEuro(euro, cb_auswahl.getSelectedIndex()); // setText braucht einen String als Parameter tf_sonst.setText("" + sonst); } // falls das Textfeld für die Fremdwährung Auslöser des ActionEvents war... else if(e.getSource() == tf_sonst){ sonst = Double.parseDouble(tf_sonst.getText()); euro = EuroConverter.convertToEuro(sonst, cb_auswahl.getSelectedIndex()); tf_euro.setText("" + euro); } } } public static void main(String[] args){ JFrame fenster = new JFrame(); fenster.setTitle("Euro-Rechner"); fenster.setContentPane(new EuroRechner()); fenster.pack(); fenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); fenster.setVisible(true); } }
public class EuroConverter {
// Währungs-Kennungen
static final int
DEM = 0, ATS = 1, FRF = 2, BEF = 3, LUF = 4, NLG = 5,
ESP = 6, PTE = 7, ITL = 8, FIM = 9, IEP = 10, GDR = 11;
// Umrechnungsfaktoren (von 2003)
private static final double[] faktor = new double[] {
1.95583, 13.7601, 6.55957, 40.3399, 2.20371,
166.386, 200.482, 1936.27, 5.94573, 0.787564, 340.750
};
private static final String[] bezeichnung = new String[] {
"Deutsche Mark", "Österreichische Schilling", "Französische Franc",
"Belgische Franc", "Luxemburgische Franc", "Niederländische Gulden",
"Spanische Peseten", "Portugiesische Escudos", "Italienische Lire",
"Finnische Mark", "Irische Pfund", "Griechische Drachmen"
};
// liefert die Bezeichnung zur Währungs-Kennung 'kennung'
static String getBezeichnung(int kennung){
return bezeichnung[kennung];
}
// konvertiert den Euro-Wert 'euro' in die durch die
// Währungs-Kennung 'kennung' spezifizierte Währung
static double convertFromEuro(double euro, int kennung){
return faktor[kennung] * euro;
}
// konvertiert den Wert 'sonst', der durch die
// Währungs-Kennung spezifizierten Währung in den
// entsprechenden Euro-Wert
static double convertToEuro(double sonst, int kennung){
return sonst / faktor[kennung];
}
}
» drucken: pdf | html
|