vorheriges KapitelInhaltsverzeichnisStichwortverzeichnisFeedbacknächstes Kapitel


Woche 1

Tag 21


Ereignisbehandlung mit Swing

In diesem Kapitel stehen zwei große Ereignisse an: Der Abschluß Ihrer dreiwöchigen Reise durch die Programmiersprache Java und die Ereignisse, die Sie in Swing-Programmen zu behandeln lernen.

Um eine funktionierende Java-Benutzeroberfläche in ein funktionierendes Java-Programm zu verwandeln, müssen Sie der Oberfläche beibringen, auf Ereignisse zu reagieren, die vom Benutzer ausgelöst werden.

Sie haben bereits mit Ereignissen zu tun gehabt, als Sie gelernt haben, Mausklicks und andere Benutzereingaben mit dem Abstract Windowing Toolkit zu behandeln. Dieses Wissen wurde verwendet, um Java-1.02-kompatible Applets zu erstellen.


Swing behandelt im Vergleich zu Java 1.02 Ereignisse anders, und zwar mit Klassen, die als Event Listener bezeichnet werden. Heute lernen Sie, wie Sie Listener aller Arten in Ihre Swing-Programme einfügen. Zu diesen Listenern gehören u.a. solche, die auf Aktionsereignisse, Mausereignisse und andere Interaktionen hören.

Wenn Sie durch sind, feiern Sie dieses Ereignis mit der Vervollständigung einer Java- Applikation mit den Swing-Klassen.

Das Hauptereignis

In dem Ereignisbehandlungssystem, das Sie letzte Woche kennengelernt haben, wurden Ereignisse mit einem Satz von Methoden, die allen Komponenten zur Verfügung stehen, behandelt. Methoden wie mouseDown(), keyDown() und action() können in jedem AWT-Programm, das diese Ereignisse behandeln will, überschrieben werden.

Dieses System zur Ereignisbehandlung bezieht sich nur auf Java 1.02, da in den Folgeversionen eine stark verbesserte Lösung für die Ereignisbehandlung angeboten wurde.

Das neue System verwenden Sie, um Swing-Applikationen zu erstellen.

Event Listener

Wenn eine Klasse im Ereignisbehandlungsmodell von Java 1.2 auf ein Ereignis reagieren will, muß diese eine Schnittstelle implementieren, die diese Ereignisse verarbeitet. Diese Schnittstellen werden als Event Listener bezeichnet.

Jeder Listener behandelt eine bestimmte Ereignisart. Eine Klasse kann so viele Listener implementieren, wie benötigt werden.

Die folgenden Event Listener stehen zur Verfügung:

Die folgende Klasse ist so deklariert, daß sie sowohl Aktions- als auch Textereignisse behandeln kann:

public class Suspense extends JFrame implements ActionListener,
     TextListener {
    // ...
}

Das Paket java.awt.event beinhaltet alle der elementaren Event Listener wie auch die Objekte, die spezielle Ereignisse repräsentieren. Um diese Klassen in Ihren Programmen zu verwenden, können Sie sie einzeln importieren oder eine Anweisung wie die folgende verwenden:

import java.awt.event.*;

Komponenten einrichten

Indem Sie eine Klasse zu einem Event Listener machen, haben Sie eine bestimmte Ereignisart festgelegt, auf die diese Klasse hört. Allerdings wird dies nie passieren, wenn Sie nicht einen zweiten Schritt folgen lassen: Es muß ein passender Listener in die Komponente eingefügt werden. Dieser Listener erzeugt die Ereignisse, wenn die Komponente verwendet wird.

Nachdem eine Komponente erzeugt wurde, können Sie eine der folgenden Methoden für die Komponente aufrufen, um dieser einen Listener zuzuordnen:

Eine Komponente zu verändern, nachdem sie in einen Container eingefügt wurde, ist ein Fehler, der einem in einem Java-Programm sehr leicht unterlaufen kann. Sie müssen einer Komponente Listener hinzufügen und alle anderen Konfigurationen vornehmen, bevor Sie diese in irgendeinen Container einfügen. Andernfalls werden diese Einstellungen bei der Ausführung des Programms mißachtet.

Das folgende Beispiel erzeugt ein JButton-Objekt und verknüpft es mit einem Listener für Aktionsereignisse:

JButton zap = new JButton("Zap");
zap.addActionListener(this);

Alle der unterschiedlichen Methoden erwarten ein Argument: das Objekt, das auf Ereignisse dieser Art hört. Wenn Sie this verwenden, zeigt dies, daß die aktuelle Klasse der Event Listener ist. Sie könnten auch ein anderes Objekt angeben, solange dessen Klasse die geeigneten Listener-Schnittstellen implementiert.

Methoden für die Ereignisbehandlung

Wenn Sie eine Schnittstelle mit einer Klasse verknüpfen, muß diese Klasse auch alle Methoden der Schnittstelle implementieren.

Im Fall der Event Listener wird jede der Methoden automatisch aufgerufen, sobald das korrespondierende Benutzereignis eintritt.

Die ActionListener-Schnittstelle besitzt nur eine einzige Methode actionPerformed() . Alle Klassen, die ActionListener implementieren, müssen über diese Methode mit einer Struktur wie der folgenden verfügen:

public void actionPerformed(ActionEvent evt) {
    // Ereignis hier verarbeiten
}

Wenn nur eine Komponente in Ihrer grafischen Benutzeroberfläche einen Listener für Aktionsereignisse besitzt, kann diese actionPerformed()-Methode zur Behandlung der Ereignisse, die von dieser Komponente erzeugt werden, verwendet werden.

Wenn mehr als eine Komponente einen Listener für Aktionsereignisse hat, müssen Sie in der Methode herausfinden, welche Komponente verwendet wurde, und anschließend entsprechend darauf reagieren.

Sie haben vielleicht bemerkt, daß der Methode ein ActionEvent-Objekt als Argument beim Aufruf übergeben wird. Dieses Objekt kann dazu verwendet werden, Details über die Komponente zu ermitteln, die das Ereignis erzeugt hat.

ActionEvent-Objekt und alle anderen Objekte für Ereignisse sind Teil des Paketes java.awt.event und Subklassen der Klasse EventObject.

Jeder Methode zur Ereignisbehandlung wird ein Ereignisobjekt irgendeiner Art übergeben. Die Methode getSource() des Objekts kann dazu verwendet werden, die Komponente zu ermitteln, die das Ereignis gesendet hat, wie das im folgenden Beispiel gezeigt wird:

public void actionPerformed(ActionEvent evt) {
    Object src = evt.getSource();
}

Das Objekt, das von der Methode getSource() zurückgegeben wird, kann über den Operator == mit Komponenten verglichen werden. Die folgenden Anweisungen könnten in dem vorigen actionPerformed()-Beispiel verwendet werden:

if (src == quitButton)
    quitProgram();
else if (src == sortRecords)
    sortRecords();

Dieses Beispiel ruft die Methode quitProgramm() auf, wenn das Objekt quitButton das Ereignis erzeugt hat, bzw. die Methode sortRecords() wird aufgerufen, wenn das Ereignis von der Schaltfläche sortRecord stammt.

Viele Methoden zur Ereignisbehandlung werden für die einzelnen Ereignisarten bzw. die verschiedenen Komponenten unterschiedliche Methoden aufrufen. Dadurch ist die Methode zur Ereignisbehandlung leichter zu lesen. Zusätzlich können, wenn sich mehrere Ereignisbehandlungsmethoden in der Klasse befinden, diese dieselben Methoden aufrufen, um bestimmte Aktionen auszuführen.

Eine andere nützliche Technik innerhalb einer Ereignisbehandlungsmethode ist es, das Schlüsselwort instanceof zu verwenden, um zu prüfen, welche Art von Komponente ein Ereignis ausgelöst hat. Das folgende Beispiel könnte in einem Programm mit einer Schaltfläche und einem Textfeld, die beide Aktionsereignisse erzeugen, verwendet werden:

void actionPerformed(ActionEvent evt) {
    Object src = evt.getSource();
    if (src instanceof JTextField)
        calculateScore();
    else if (src instanceof JButton)
        quitProgram();
}

Das Programm in Listing 21.1 verwendet das Applikationsgerüst aus dem gestrigen Kapitel, um einen JFrame zu erzeugen und Komponenten in diesen einzufügen. Das Programm selbst verfügt über zwei JButton-Komponenten, die verwendet werden, um den Text in der Titelleiste des Frames zu ändern.

Listing 21.1: Der gesamte Quelltext von ChangeTitle.java

 1: import java.awt.event.*;
 2: import javax.swing.*;
 3: import java.awt.*;
 4:
 5: public class ChangeTitle extends JFrame implements ActionListener {
 6:     JButton b1 = new JButton("Rosencrantz");
 7:     JButton b2 = new JButton("Guildenstern");
 8:
 9:     public ChangeTitle() {
10:         super("Title Bar");
11:
12:         b1.addActionListener(this);
13:         b2.addActionListener(this);
14:         JPanel pane = new JPanel();
15:         pane.add(b1);
16:         pane.add(b2);
17:
18:         setContentPane(pane);
19:     }
20:
21:     public static void main(String[] args) {
22:         JFrame frame = new ChangeTitle();
23:
24:         WindowListener l = new WindowAdapter() {
25:             public void windowClosing(WindowEvent e) {
26:                 System.exit(0);
27:             }
28:         };
29:         frame.addWindowListener(l);
30:
31:         frame.pack();
32:         frame.setVisible(true);
33:     }
34:
35:     public void actionPerformed(ActionEvent evt) {
36:         Object source = evt.getSource();
37:         if (source == b1)
38:             setTitle("Rosencrantz");
39:         else if (source == b2)
40:             setTitle("Guildenstern");
41:         repaint();
42:     }
43: }

Die Applikation sehen Sie in Abbildung 21.1.


Abbildung 21.1:
Die ChangeTitle-Applikation

Nur 12 Zeilen waren nötig, um in dieser Applikation auf Aktionsereignisse zu reagieren:

Mit Methoden arbeiten

Der folgende Abschnitt beschreibt die Struktur der einzelnen Methoden zur Ereignisbehandlung und die Methoden, die darin verwendet werden können.

Neben den Methoden, die beschrieben werden, kann die getSource()-Methode mit allen Ereignisobjekten verwendet werden, um das Objekt zu ermitteln, das ein Ereignis erzeugt hat.

Aktionsereignisse

Aktionsereignisse treten auf, wenn ein Benutzer eine Aktion mit einer der folgenden Komponenten ausführt: JButton, JCheckBox, JComboBox, JTextField oder JRadioButton .

Eine Klasse muß die ActionListener-Schnittstelle implementieren, um diese Ereignisse zu behandeln. Zusätzlich muß die Methode addActionListener() für jede Komponente aufgerufen werden, die ein Aktionsereignis erzeugen soll - es sei denn, Sie wollen die Aktionsereignisse einer Komponente ignorieren.

In der ActionListener-Schnittstelle befindet sich lediglich eine Methode: actionPerformed(ActionEvent) . Diese hat die folgende Form:

public void actionPerformed(ActionEvent evt) {
   // ...
}

Zusätzlich zu der Methode getSource() können Sie die Methode getActionCommand() des ActionEvent-Objekts verwenden, um mehr Informationen über die Quelle eines Ereignisses zu erhalten.

Der standardmäßige Rückgabewert dieser Methode (das Action Command der Komponente) ist der Text, der einer Komponente zugewiesen ist, wie z.B. die Beschriftung einer Schaltfläche - einem JButton-Objekt. Sie können auch ein anderes Action Command für eine Komponente festlegen, indem Sie deren setActionCommand(String)- Methode aufrufen. Das String-Argument sollte der Text für das Action Command sein.

Die folgende Anweisung erzeugt z.B. ein JButton- und ein JTextField-Objekt und weist beiden das Action Command "Sort Files" zu:

JButton sort = new JButton("Sort");
JTextField name = new JTextField();
sort.setActionCommand("Sort Files");
name.setActionCommand("Sort Files");


Action Commands sind sehr hilfreich, wenn Sie ein Programm schreiben, in dem mehr als eine Komponente dasselbe Verhalten auslösen soll. Ein Beispiel hierfür wäre ein Programm mit einer Schaltfläche Beenden und der Option Beenden in einem Menü. Indem Sie beiden Komponenten dasselbe Action Command geben, können Sie diese mit demselben Code behandeln.

Adjustment-Ereignisse

Adjustment-Ereignisse treten auf, wenn der Wert einer JScrollBar-Komponente mit den Pfeilen der Bildlaufleiste, dem Schieber oder durch Klicks auf die Bildlaufleiste verändert wird. Um diese Ereignisse zu behandeln, muß eine Klasse die Schnittstelle AdjustmentListener implementieren.

In der Schnittstelle AdjustmentListener gibt es nur eine Methode: adjustmentValueChanged(AdjustmentEvent) . Diese hat die folgende Form:

public void adjustmentValueChanged(AdjustmentEvent evt) {
   // ...
}

Um den aktuellen Wert der JScrollBar-Komponente in dieser Ereignisbehandlungsmethode zu ermitteln, rufen Sie die Methode getValue() des AdjustmentEvent-Objekts auf. Diese Methode gibt einen Integer zurück, der den Wert der Bildlaufleiste widerspiegelt.

Sie können auch ermitteln, was der Benutzer mit der Bildlaufleiste gemacht hat. Dazu verwenden Sie die Methode getAdjustmentType() des AdjustmentEvent-Objekts. Diese gibt einen von fünf Werten zurück. Jeder davon ist eine Klassenvariable der Klasse Adjustment:

Das Programm in Listing 21.2 illustriert die Verwendung der AdjustmentListener- Schnittstelle. Dem Frame werden eine Bildlaufleiste und ein nichteditierbares Textfeld hinzugefügt. In diesem Feld wird eine Meldung angezeigt, wann immer sich der Wert der Bildlaufleiste verändert.

Listing 21.2: Der gesamte Quelltext von WellAdjusted.java

 1: import java.awt.event.*;
 2: import javax.swing.*;
 3: import java.awt.*;
 4:
 5: public class WellAdjusted extends JFrame implements AdjustmentListener {
 6:     BorderLayout bord = new BorderLayout();
 7:     JTextField value = new JTextField();
 8:     JScrollBar bar = new JScrollBar(SwingConstants.HORIZONTAL,
 9:         50, 10, 0, 100);
10:
11:     public WellAdjusted() {
12:         super("Well Adjusted");
13:
14:         bar.addAdjustmentListener(this);
15:         value.setHorizontalAlignment(SwingConstants.CENTER);
16:         value.setEditable(false);
17:         JPanel pane = new JPanel();
18:         pane.setLayout(bord);
19:         pane.add(value, "South");
20:         pane.add(bar, "Center");
21:
22:         setContentPane(pane);
23:     }
24:
25:     public static void main(String[] args) {
26:         JFrame frame = new WellAdjusted();
27:
28:         WindowListener l = new WindowAdapter() {
29:             public void windowClosing(WindowEvent e) {
30:                 System.exit(0);
31:             }
32:         };
33:         frame.addWindowListener(l);
34:
35:         frame.pack();
36:         frame.setVisible(true);
37:     }
38:
39:     public void adjustmentValueChanged(AdjustmentEvent evt) {
40:         Object source = evt.getSource();
41:         if (source == bar) {
42:             int newValue = bar.getValue();
43:             value.setText("" + newValue);
44:         }
45:         repaint();
46:     }
47: }

Abbildung 21.2 zeigt einen Screenshot der Applikation.


Abbildung 21.2:
Die Ausgabe der WellAdjusted-Applikation


Sie werden sich vielleicht fragen, warum sich in dem Aufruf der Methode setText() in Zeile 43 dieses Programms ein Paar leerer Anführungszeichen befindet. Ein solches Paar leerer Anführungszeichen wird als null-String bezeichnet. Dieser wird mit dem Integer newValue verkettet, um das Argument in einen String zu verwandeln. Java behandelt das Ergebnis immer als String. Wie Sie sich vielleicht erinnern werden, ist dies immer der Fall, wenn ein String und ein Nicht-String miteinander verkettet werden. Der null-String ist eine Abkürzung, wenn Sie etwas anzeigen wollen, das kein String ist.

Fokusereignisse

Fokusereignisse treten auf, wenn eine Komponente den Eingabefokus erhält oder verliert. Als Fokus bezeichnet man den Zustand, in dem eine Komponente Tastatureingaben entgegennehmen kann. Wenn eines der Felder den Fokus hat (in einer Benutzerschnittstelle mit mehreren editierbaren Textfeldern), dann blinkt der Cursor in diesem Feld. Jeder Text, der eingegeben wird, richtet sich an diese Komponente.

Der Begriff Fokus bezieht sich auf alle Komponenten, die Eingaben empfangen können. Bei einem JButton-Objekt erscheint eine gepunktete Linie um das Objekt herum, wenn dieses den Fokus hat.

Um Fokusereignisse zu behandeln, muß eine Klasse die FocusListener-Schnittstelle implementieren. Diese Schnittstelle verfügt über zwei Methoden: focusGained(FocusEvent) und focusLost(FocusEvent). Diese haben die folgende Form:

public void focusGained(FocusEvent evt) {
   // ...
}

public void focusLost(FocusEvent evt) {
   // ...
}

Um festzustellen, welches Objekt den Fokus erhalten bzw. diesen verloren hat, rufen Sie die Methode getSource() des FocusEvent-Objekts auf, das als Argument an die Methoden focusGained(FocusEvent) und focusLost(FocusEvent) übergeben wird.

Item-Ereignisse


Item-Ereignisse treten auf, wenn ein Element in einer der folgenden Komponenten gewählt oder abgewählt wird: JButton, JCheckBox, JComboBox oder JRadioButton. Eine Klasse muß die Schnittstelle ItemListener implementieren, um diese Ereignisse behandeln zu können.

Die Schnittstelle ItemListener verfügt nur über eine Methode: itemStateChanged(ItemEvent) . Diese hat die folgende Form:

void itemStateChanged(ItemEvent evt) {
   // ...
}

Um festzustellen, welches Element das Ereignis ausgelöst hat, rufen Sie die Methode getItem() des ItemEvent-Objekts auf.

Sie können auch ermitteln, ob das Element gewählt oder abgewählt wurde, indem Sie die Methode getStateChange() aufrufen. Diese Methode gibt einen Integer zurück, der einer der beiden Klassenvariablen ItemEvent.DESELECTED oder ItemEvent.SELECTED entspricht.

Die Anwendung von Item-Ereignissen wird in Listing 21.3 illustriert. Die Applikation SelectItem zeigt die Auswahl, die in einem Kombinationslistenfeld getroffen wird, in einem Textfeld an.

Listing 21.3: Der gesamte Quelltext von SelectItem.java

 1: import java.awt.event.*;
 2: import javax.swing.*;
 3: import java.awt.*;
 4:
 5: public class SelectItem extends JFrame implements ItemListener {
 6:     BorderLayout bord = new BorderLayout();
 7:     JTextField result = new JTextField(27);
 8:     JComboBox pick = new JComboBox();
 9:
10:     public SelectItem() {
11:         super("Select Item");
12:
13:         pick.addItemListener(this);
14:         pick.addItem("Navigator");
15:         pick.addItem("Internet Explorer");
16:         pick.addItem("Opera");
17:         pick.setEditable(false);
18:         result.setHorizontalAlignment(SwingConstants.CENTER);
19:         result.setEditable(false);
20:         JPanel pane = new JPanel();
21:         pane.setLayout(bord);
22:         pane.add(result, "South");
23:         pane.add(pick, "Center");
24:
25:         setContentPane(pane);
26:     }
27:
28:     public static void main(String[] args) {
29:         JFrame frame = new SelectItem();
30:
31:         WindowListener l = new WindowAdapter() {
32:             public void windowClosing(WindowEvent e) {
33:                 System.exit(0);
34:             }
35:         };
36:         frame.addWindowListener(l);
37:
38:         frame.pack();
39:         frame.setVisible(true);
40:     }
41:
42:     public void itemStateChanged(ItemEvent evt) {
43:         Object source = evt.getSource();
44:         if (source == pick) {
45:             Object newPick = evt.getItem();
46:             result.setText(newPick.toString() + " is the selection.");
47:         }
48:         repaint();
49:     }
50: }

Abbildung 21.3 zeigt diese Applikation, wobei das Element Opera die aktuelle Auswahl in dem Kombinationslistenfeld darstellt. Mit der Methode toString() des Objekts, das von der Methode getItem() zurückgegeben wird, wird der Text dieses Objekts ermittelt.


Abbildung 21.3:
Die Ausgabe der SelectItem-Applikation

Tastaturereignisse

Tastaturereignisse treten auf, wenn eine Taste auf der Tastatur gedrückt wird. Jede beliebige Komponente kann diese Ereignisse erzeugen. Eine Klasse muß die Schnittstelle KeyListener implementieren, um diese Ereignisse zu unterstützen.

Die KeyListener-Schnittstelle verfügt über drei Methoden: keyPressed(KeyEvent), keyReleased(KeyEvent) und keyTyped(KeyEvent). Diese haben die folgende Form:

public void keyPressed(KeyEvent evt) {
    // ...
}

public void keyReleased(KeyEvent evt) {
    // ...
}

public void keyTyped(KeyEvent evt) {
    // ...
}

Die Methode getKeyChar() der Klasse KeyEvent gibt das Zeichen der Taste zurück, die dieses Ereignis ausgelöst hat. Falls es kein Unicode-Zeichen gibt, das die Taste repräsentiert, gibt die Methode getKeyChar() einen Zeichenwert zurück, der der Klassenvariablen KeyEvent.CHAR_UNDEFINED entspricht.

Mausereignisse

Mausereignisse werden durch viele verschiedene Arten von Benutzerinteraktionen erzeugt:

Jede Komponente kann diese Ereignisse erzeugen. Um sie zu behandeln, muß eine Klasse die Schnittstelle MouseListener implementieren. Diese Schnittstelle verfügt über fünf Methoden:

Dabei entspricht die Form aller dieser Methoden der von mouseReleased(MouseEvent) :

public void mouseReleased(MouseEvent evt) {
    // ...
}

Die folgenden Methoden bietet das MouseEvent-Objekt:

MouseMotion-Ereignisse

MouseMotion-Ereignisse treten auf, wenn die Maus über eine Komponente bewegt wird. Wie auch die anderen Mausereignisse können diese von jeder Komponente erzeugt werden. Um diese Ereignisse zu unterstützen, muß eine Klasse die Schnittstelle MouseMotionListener implementieren.

Die Schnittstelle MouseMotionListener verfügt über zwei Methoden: mouseDragged(MouseMotionEvent) und mouseMoved(MouseMotionEvent). Diese Methoden haben die folgende Form:

public void mouseDragged(MouseEvent evt) {
    // ...
}

public void mouseMoved(MouseEvent evt) {
    // ...
}

Anders als die anderen Event-Listener-Schnittstellen, mit denen Sie es bisher zu tun hatten, hat MouseMotionListener keinen eigenen Ereignistyp. Statt dessen werden MouseEvent-Objekte verwendet.

Aus diesem Grund können Sie dieselben Methoden wie bei Mausereignissen verwenden: getClick(), getPoint(), getX() und getY().

Fensterereignisse

Fensterereignisse treten auf, wenn ein Benutzer Fenster öffnet oder schließt. Unter dem Begriff Fenster werden Objekte wie z.B. JFrame oder JWindow verstanden. Eine Klasse muß die Schnittstelle WindowListener implementieren, um diese Ereignisse zu unterstützen.

Die WindowListener-Schnittstelle verfügt über sieben Methoden:

Alle haben sie dieselbe Form wie die Methode windowOpened(WindowEvent):

public void windowOpened(WindowEvent evt) {
    // ...
}

Die Methoden windowClosing() und windowClosed() sind sich ähnlich, allerdings wird erstere aufgerufen, wenn sich das Fenster schließt, und die zweite, nachdem das Fenster geschlossen ist. Sie können in der Methode windowClosing() das Schließen des Fensters verhindern.

Ein Beispiel: die SwingColorTest-Applikation

Gestern haben Sie eine grafische Benutzeroberfläche für das RGB-zu-HSB-Konvertierungs-Programm mit Swing-Komponenten erstellt.

Um mehr Erfahrung im Umgang mit dem Ereignisbehandlungsmodell von Swing zu bekommen, verwandeln Sie die Benutzerschnittstelle von SwingColorTest in ein funktionierendes Programm.

Gestern haben Sie zwei Klassen für dieses Projekt erzeugt:

SwingColorTest und SwingColorControls.

SwingColorTest beinhaltet das Hauptfenster der Applikation und die main()-Methode, mit der das Fenster eingerichtet wird. SwingColorControls, eine Hilfsklasse, ist ein Panel, das drei Labels und drei Textfelder beinhaltet, die zur Wahl der Farbe verwendet werden.

Sämtliche Benutzereingaben finden in den Objekten der Klasse SwingColorControls statt - über die Textfelder werden sRGB- oder HSB-Werte definiert.

Aus diesem Grund wird das gesamte Verhalten für die Ereignisbehandlung in die Klasse SwingColorControls eingefügt.

Als erstes müssen Sie dafür sorgen, daß die Klasse SwingColorControls zwei Arten von Ereignissen behandelt: Aktionsereignisse und Fokusereignisse. Mit der Anweisung implements müssen in der Klassendeklaration die Schnittstellen ActionListener und FocusListener implementiert werden. Dies ist im folgenden gezeigt:

class SwingColorControls extends JPanel
    implements ActionListener, FocusListener {

Als nächstes müssen die entsprechenden Listener den Textfeldern (tfield1, tfield2 und tfield3) in der Klasse hinzugefügt werden. Diese Listener müssen Sie hinzufügen, nachdem die Textfelder erzeugt wurden und bevor diese in einen Container eingefügt werden. Dazu können Sie die folgenden Anweisungen verwenden:

tfield1.addFocusListener(this);
tfield2.addFocusListener(this);
tfield3.addFocusListener(this);
tfield1.addActionListener(this);
tfield2.addActionListener(this);
tfield3.addActionListener(this);

Schließlich müssen Sie noch alle Methoden, die in den beiden Schnittstellen, die diese Klasse implementiert, definiert sind, hinzufügen:

actionPerformed(ActionEvent), focusLost(FocusEvent) und focusGained(FocusEvent) .

Die SwingColorControls-Objekte werden zur Eingabe von numerischen Werten für eine Farbe verwendet. Die Eingabe von Werten sorgt dafür, daß die Farbe auf einem Panel angezeigt wird. Außerdem wird das zweite SwingColorControls-Objekt so aktualisiert, daß sich die Änderung der Farbe in den darin befindlichen Zahlenwerten widerspiegelt.

Es gibt zwei Möglichkeiten für den Benutzer, die Auswahl einer neuen Farbe abzuschließen - durch Drücken der Eingabetaste innerhalb eines Textfeldes, wodurch ein Aktionsereignis ausgelöst wird, und durch Verlassen des Feldes, um den Wert eines anderen Feldes zu editieren, was zu einem Fokusereignis führt.

Die folgenden Anweisungen bilden die actionPerformed()- und focusLost()-Methoden, die Sie in Ihrer Klasse einfügen sollten:

public void actionPerformed(ActionEvent evt) {
    if (evt.getSource() instanceof TextField)
        frame.update(this);
}
public void focusLost(FocusEvent evt) {
    frame.update(this);
}

Da das Ereignis, das bei Erhalt des Fokus erzeugt wird, hier nicht behandelt wird, die dazugehörige Methode (focusGained()) der Schnittstelle aber implementiert werden muß, sollten Sie eine leere Methode einfügen:

public void focusGained(FocusEvent evt) { }

Die Ereignisbehandlungsmethoden, die in SwingColorControls eingefügt wurden, rufen eine Methode in der Klasse SwingColorTest auf (update(SwingColorControls) ).

Diese Methode beinhaltet keinerlei Verhaltensweisen zur Ereignisbehandlung - Sie aktualisiert das Farbmuster und die SwingColorControls-Objekte, damit diese die Farbänderung widerspiegeln. Dies entspricht der Version, die Sie am Tag 14 erstellt haben.

Listing 21.4 beinhaltet die Applikation mit den beiden Klassen SwingColorTest und SwingColorControls.

Listing 21.4: Der gesamte Quelltext von SwingColorTest.java

 1: import java.awt.*;
 2: import java.awt.event.*;
 3: import javax.swing.*;
 4:
 5: public class SwingColorTest extends JFrame {
 6:     SwingColorControls RGBcontrols, HSBcontrols;
 7:     JPanel swatch;
 8:
 9:     public SwingColorTest() {
10:         super("Color Test");
11:
12:         JPanel pane = new JPanel();
13:         pane.setLayout(new GridLayout(1, 3, 5, 15));
14:         swatch = new JPanel();
15:         swatch.setBackground(Color.black);
16:         RGBcontrols = new SwingColorControls(this, "Red",
17:             "Green", "Blue");
18:         HSBcontrols = new SwingColorControls(this, "Hue",
19:             "Saturation", "Brightness");
20:         pane.add(swatch);
21:         pane.add(RGBcontrols);
22:         pane.add(HSBcontrols);
23:
24:         setContentPane(pane);
25:     }
26:
27:     public static void main(String[] args) {
28:         JFrame frame = new SwingColorTest();
29:
30:         WindowListener l = new WindowAdapter() {
31:             public void windowClosing(WindowEvent e) {
32:                 System.exit(0);
33:             }
34:         };
35:         frame.addWindowListener(l);
36:
37:         frame.pack();
38:         frame.setVisible(true);
39:     }
40:
41:     public Insets getInsets() {
42:         return new Insets(10, 10, 10, 10);
43:     }
44:
45:     void update(SwingColorControls controlPanel) {
46:         Color c;
47:         // Die String-Werte aus den Textfeldern auslesen und in ints
            // konvertieren
48:         int value1 = Integer.parseInt(controlPanel.tfield1.getText());
49:         int value2 = Integer.parseInt(controlPanel.tfield2.getText());
50:         int value3 = Integer.parseInt(controlPanel.tfield3.getText());
51:
52:         if (controlPanel == RGBcontrols) {
53:             // RGB geändert, HSB aktualisieren
54:             c = new Color(value1, value2, value3);
55:
56:             // RGB-Werte in HSB-Werte konvertieren
57:             float[] HSB = Color.RGBtoHSB(value1, value2, value3,
58:                 (new float[3]));
59:             HSB[0] *= 360;
60:             HSB[1] *= 100;
61:             HSB[2] *= 100;
62:
63:             // HSB-Felder zurücksetzen
64:             HSBcontrols.tfield1.setText(String.valueOf((int)HSB[0]));
65:             HSBcontrols.tfield2.setText(String.valueOf((int)HSB[1]));
66:             HSBcontrols.tfield3.setText(String.valueOf((int)HSB[2]));
67:
68:         } else {
69:             // HSB geändert, RGB aktualisieren
70:             c = Color.getHSBColor((float)value1 / 360,
71:                 (float)value2 / 100, (float)value3 / 100);
72:
73:             // RGB-Felder zurücksetzen
74:             RGBcontrols.tfield1.setText(String.valueOf(c.getRed()));
75:             RGBcontrols.tfield2.setText(String.valueOf(c.getGreen()));
76:             RGBcontrols.tfield3.setText(String.valueOf(c.getBlue()));
77:         }
78:
79:         // Farbanzeiger aktualisieren
80:         swatch.setBackground(c);
81:         swatch.repaint();
82:     }
83: }
84:
85: class SwingColorControls extends JPanel
86:     implements ActionListener, FocusListener {
87:
88:     SwingColorTest frame;
89:     JTextField tfield1, tfield2, tfield3;
90:
91:     SwingColorControls(SwingColorTest parent,
92:         String l1, String l2, String l3) {
93:
94:         frame = parent;
95:         setLayout(new GridLayout(3,2,10,10));
96:         tfield1 = new JTextField("0");
97:         tfield2 = new JTextField("0");
98:         tfield3 = new JTextField("0");
99:         tfield1.addFocusListener(this);
100:         tfield2.addFocusListener(this);
101:         tfield3.addFocusListener(this);
102:         tfield1.addActionListener(this);
103:         tfield2.addActionListener(this);
104:         tfield3.addActionListener(this);
105:         add(new JLabel(l1, JLabel.RIGHT));
106:         add(tfield1);
107:         add(new JLabel(l2, JLabel.RIGHT));
108:         add(tfield2);
109:         add(new JLabel(l3, JLabel.RIGHT));
110:         add(tfield3);
111:     }
112:
113:     public Insets getInsets() {
114:         return new Insets(10, 10, 0, 0);
115:     }
116:
117:     public void actionPerformed(ActionEvent evt) {
118:         if (evt.getSource() instanceof TextField)
119:             frame.update(this);
120:     }
121:
122:     public void focusLost(FocusEvent evt) {
123:         frame.update(this);
124:     }
125:
126:     public void focusGained(FocusEvent evt) { }
127: }

Abbildung 21.4 zeigt das fertige Produkt.


Abbildung 21.4:
Die SwingColorTest-Applikation

Zusammenfassung

Intern ist das Ereignisbehandlungssystem von Swing wesentlich robuster und einfacher zu erweitern, um neue Arten der Interaktion mit dem Benutzer zu verarbeiten.

Nach außen sollte das System auch vom Standpunkt der Programmierung her mehr Sinn machen. Die Ereignisbehandlung wird einem Programm immer über dieselben Schritte hinzugefügt:

Sobald Sie diese Schritte kennen, können Sie mit jeder der verschiedenen Listener- Schnittstellen und Ereignis-Klassen arbeiten. Außerdem können Sie den Umgang mit neuen Listenern leicht erlernen, sobald diese in Swing hinzugefügt werden.

Dies bringt uns zu dem Hauptereignis: Der Abschluß der 21tägigen Reise durch die Sprache Java. Jetzt, da Sie die Gelegenheit hatten, mit der Syntax und den Kernklassen, die Java ausmachen, zu arbeiten, sind Sie bereit, die wirklich harten Nüsse zu knacken: Ihre eigenen Programme.

Herzlichen Glückwunsch! Nachdem Sie nun eine Einführung in die wohl bemerkenswerteste Programmiersprache des letzten Jahrzehnts erhalten haben, ist es an Ihnen, bemerkenswerte Dinge damit zu tun.

Während Sie viel Zeit in Ihre eigenen Programme investieren, neue Features lernen und die Java-Klassen in Ihren eigenen Paketen erweitern, werden Sie einen weiteren Grund kennenlernen, warum der Name Java gut gewählt war:

Java kann, wie sein koffeinhaltiges Gegenstück, abhängig machen.

»Laß' es nicht so enden. Sag' ihnen, daß ich etwas gesagt habe.«

- Die letzten Wort von Pancho Villa (1877-1923)

Fragen und Antworten

Frage:
Kann man das Verhalten zur Ereignisbehandlung eines Programmes nicht in eine eigene Klasse auslagern, anstelle diese in den Code für die Benutzerschnittstelle einzufügen?

Frage:
Man kann, und viele Programmierer werden Ihnen sagen, daß es eine gute Methode ist, wenn Sie Ihre Programme so entwerfen. Durch die Trennung des Entwurfs der Benutzerschnittstelle von dem Code zur Ereignisbehandlung wird es möglich, diese beiden Bereiche getrennt voneinander zu entwickeln - die SwingColorTest-Applikation von heute zeigt den gegenteiligen Ansatz. Dies vereinfacht die Pflege des Projektes, da zusammengehörige Verhaltensweisen gruppiert und von Verhaltensweisen, die damit nicht im Zusammenhang stehen, isoliert sind.



vorheriges KapitelInhaltsverzeichnisStichwortverzeichnisFeedbacknächstes Kapitel


Ein Imprint des Markt&Technik Buch- und Software-Verlag GmbH.
Elektronische Fassung des Titels: Java 2 in 21 Tagen, ISBN: 3-8272-5578-3