Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 3. Auflage
<< | < | > | >> | API | Kapitel 28 - Event-Handling

## 28.1 Das Event-Handling im JDK 1.1

- 28.1 Das Event-Handling im JDK 1.1
  - 28.1.1 Grundlagen
  - 28.1.2 Ereignistypen
  - 28.1.3 Ereignisempfänger
  - 28.1.4 Ereignisquellen
  - 28.1.5 Adapterklassen
  - 28.1.6 Zusammenfassung
    - Focus-Ereignisse
    - Key-Ereignisse
    - Mouse-Ereignisse
    - MouseMotion-Ereignisse
    - Component-Ereignisse
    - Container-Ereignisse
    - Window-Ereignisse
    - Action-Ereignisse
    - Adjustment-Ereignisse
    - Item-Ereignisse
    - Text-Ereignisse

### 28.1.1 Grundlagen

Bei der Programmierung unter einer grafischen Oberfläche erfolgt die Kommunikation zwischen Betriebssystem und Anwendungsprogramm zu einem wesentlichen Teil durch das Versenden von Nachrichten. Die Anwendung wird dabei über alle Arten von Ereignissen und Zustandsänderungen vom Betriebssystem informiert. Dazu zählen beispielsweise Mausklicks, Bewegungen des Mauszeigers, Tastatureingaben oder Veränderungen an der Größe oder Lage des Fensters.

Bei der Verarbeitung des Nachrichtenverkehrs sind zwei verschiedene Arten von Objekten beteiligt. Die Ereignisquellen (Event Sources) sind die Auslöser der Nachrichten. Eine Ereignisquelle kann beispielsweise ein Button sein, der auf einen Mausklick reagiert, oder ein Fenster, das mitteilt, daß es über das Systemmenü geschlossen werden soll. Die Reaktion auf diese Nachrichten erfolgt in den speziellen Ereignisempfängern (den EventListeners); das sind Objekte, die das zum Ereignis passende Empfänger-Interface implementieren. Damit ein Ereignisempfänger die Nachrichten einer bestimmten Ereignisquelle erhält, muß er sich bei dieser registrieren.

Dieses Kommunikationsmodell nennt sich Delegation Event Model oder Delegation Based Event Handling und wurde mit der Version 1.1 des JDK eingeführt. Im Gegensatz zum alten Modell, bei dem jedes Ereignis die Verteilermethode `handleEvent` der Klasse `Component` durchlaufen mußte und von ihr an die verschiedenen Empfänger verteilt wurde, hat dieses neue Modell zwei wesentliche Vorteile:

- Es verringert den Nachrichtenverkehr, da nur noch die Ereignisse transportiert werden, für die es Empfänger gibt. Dadurch erhöht sich potentiell die Performance des Nachrichtentransports im AWT.
- Es erlaubt eine klare Trennung zwischen Programmcode zur Oberflächengestaltung und solchem zur Implementierung der Anwendungslogik. Es erleichtert dadurch die Erzeugung von robustem Code, der auch in großen Programmen den Entwurf sauber strukturierter Ereignishandler ermöglicht.

Diesen Vorteilen steht natürlich der etwas höhere Einarbeitungsaufwand gegenüber. Während man beispielsweise im AWT 1.0 einfach die `action`-Methode des Fensters überlagerte, um auf einen Buttonklick zu reagieren, muß man nun eine `EventListener`-Klasse schreiben, instanzieren und bei der Ereignisquelle registrieren.

Zudem werden wir feststellen, daß das neue Modell eine Vielzahl von unterschiedlichen Möglichkeiten impliziert, Ereignishandler zu implementieren. Diese sind je nach Anwendungsfall unterschiedlich gut oder schlecht geeignet, den jeweiligen Nachrichtenverkehr abzubilden. Wir werden uns in diesem Kapitel insbesondere mit folgenden Entwurfsmustern beschäftigen:

- Die Fensterklasse implementiert die erforderlichen `EventListener`-Interfaces, stellt die erforderlichen Callback-Methoden zur Verfügung und registriert sich selbst bei den Ereignisquellen.
- In der Fensterklasse werden lokale oder anonyme Klassen definiert, die einen `EventListener` implementieren oder sich aus einer Adapterklasse ableiten (eine Adapterklasse implementiert ein Interface mit mehreren Methoden und erlaubt es somit abgeleiteten Klassen, nur noch die Methoden zu überlagern, die tatsächlich von Interesse sind).
- GUI-Code und Ereignisbehandlung werden vollkommen getrennt und auf unterschiedliche Klassen verteilt.
- In der Komponentenklasse werden die Methoden überlagert, die für das Empfangen und Verteilen der Nachrichten erforderlich sind.

Wir werden uns jede dieser Varianten in den nachfolgenden Abschnitten ansehen und ihre jeweiligen Einsatzmöglichkeiten anhand eines Beispiels aufzeigen. Zunächst sollen jedoch die verschiedenen Ereignistypen sowie die Ereignisempfänger und Ereignisquellen näher beleuchtet werden. Wir wollen dabei (etwas unscharf) die Begriffe Ereignis, Nachricht und Event in diesem Kapitel synonym verwenden, wenn wir innerhalb eines GUI-Programms die ausgetauschten Nachrichten oder ihre auslösenden Ereignisse meinen.

|  | Das vorliegende Kapitel beschränkt sich auf das Erläutern der grundlegenden Eigenschaften des Event-Handlings im JDK 1.1. Die Details einzelner Ereignisarten werden in den nachfolgenden Kapiteln schrittweise erklärt und zusammen mit den zugehörigen Ereignisquellen vorgestellt. |  |
Hinweis

### 28.1.2 Ereignistypen

Im Gegensatz zur Version 1.0 werden im JDK 1.1 die Ereignistypen nicht mehr durch eine einzige Klasse `Event` repräsentiert, sondern durch eine Hierarchie von Ereignisklassen, die aus der Klasse `java.util.EventObject` abgeleitet sind. Die Motivation der Java-Designer, diese Klasse in das Paket `java.util` zu legen, resultierte wohl aus der Überlegung, daß der Transfer von Nachrichten nicht allein auf den Oberflächenteil beschränkt sein muß, sondern auch zwischen anderen Elementen einer komplexen Anwendung sinnvoll sein kann. Die Klasse `java.util.EventObject` fungiert damit als allgemeine Oberklasse aller Arten von Ereignissen, die zwischen verschiedenen Programmteilen ausgetauscht werden können. Ihre einzige nennenswerte Fähigkeit besteht darin, das Objekt zu speichern, das die Nachricht ausgelöst hat, und durch Aufruf der Methode `getSource` anzugeben:

    public Object getSource()
| java.util.EventObject

Die Hierarchie der AWT-spezifischen Ereignisklassen beginnt eine Ebene tiefer mit der Klasse `AWTEvent`, die aus `EventObject` abgeleitet wurde und sich im Paket `java.awt` befindet. `AWTEvent` ist Oberklasse aller Ereignisklassen des AWT. Diese befinden sich im Paket `java.awt.event`, das damit praktisch in jede Klasse einzubinden ist, die sich mit dem Event-Handling von GUI-Anwendungen beschäftigt. Abbildung 28.1 gibt einen Überblick über die Vererbungshierarchie der Ereignisklassen.

Abbildung 28.1: Die Hierarchie der Ereignisklassen

Die Dokumentation zum JDK unterteilt diese Klassen in zwei große Hierarchien. Unterhalb der Klasse `ComponentEvent` befinden sich alle Low-Level-Ereignisse. Sie sind für den Transfer von elementaren Nachrichten zuständig, die von Fenstern oder Dialogelementen stammen. Die übrigen Klassen `ActionEvent`, `AdjustmentEvent`, `ItemEvent` und `TextEvent` werden als semantische Ereignisse bezeichnet. Sie sind nicht an ein bestimmtes GUI-Element gebunden, sondern übermitteln höherwertige Ereignisse wie das Ausführen eines Kommandos oder die Änderung eines Zustands.

|  | Ein Problem der AWT-Designer war es, einen guten Kompromiß zwischen der Größe und der Anzahl der zu implementierenden Ereignissklassen zu finden. Da der Ableitungsbaum sehr unübersichtlich geworden wäre, wenn für jedes Elementarereignis eine eigene Klasse implementiert worden wäre, hat man sich teilweise dazu entschlossen, mehrere unterschiedliche Ereignisse durch eine einzige Klasse zu realisieren. So ist beispielsweise die Klasse `MouseEvent` sowohl für Mausbewegungen als auch für alle Arten von Klick- oder Drag-Ereignissen zuständig. Mit Hilfe der Methode `getID` und der in den jeweiligen Eventklassen definierten symbolischen Konstanten kann das Programm herausfinden, um welche Art von Ereignis es sich handelt: |  |
Hinweis

    public int getID()
| java.awt.AWTEvent

Falls das Programm eigene Eventklassen definieren will und Konstanten zur Vergabe der Event-Ids vergeben muß, sollten diese oberhalb der symbolischen Konstante `RESERVED_ID_MAX` liegen.

|  | Die Eventklassen im JDK 1.1 enthalten keine frei zugänglichen Felder. Statt dessen sind alle Eigenschaften durch `set`-/`get`-Methoden gekapselt, die je nach Ereignisklasse unterschiedlich sind. So gibt es beispielsweise in `MouseEvent` die Methode `getPoint`, mit der die Mauszeigerposition abgefragt werden kann, in `KeyEvent` die Methode `getKeyChar` zur Bestimmung der gedrückten Taste und in der übergeordneten Klasse `InputEvent` die Methode `getModifiers`, mit der sowohl für Maus- als auch für Tastaturevents der Zustand der Sondertasten bestimmt werden kann. Wir werden bei der Besprechung der einzelnen Ereignisarten auf die Details eingehen. |  |
Hinweis

### 28.1.3 Ereignisempfänger

Damit ein Objekt Nachrichten empfangen kann, muß es eine Reihe von Methoden implementieren, die von der Nachrichtenquelle, bei der es sich registriert hat, aufgerufen werden können. Um sicherzustellen, daß diese Methoden vorhanden sind, müssen die Ereignisempfänger bestimmte Interfaces implementieren, die aus der Klasse `EventListener` des Pakets `java.util` abgeleitet sind. Diese `EventListener`-Interfaces befinden sich im Paket `java.awt.events`.

Je Ereignisklasse gibt es ein `EventListener`-Interface. Es definiert eine separate Methode für jede Ereignisart dieser Ereignisklasse. So besitzt beispielsweise das Interface `MouseListener` die Methoden `mouseClicked`, `mouseEntered`, `mouseExited`, `mousePressed` und `mouseReleased`, die bei Auftreten des jeweiligen Ereignisses aufgerufen werden. Abbildung 28.2 gibt eine Übersicht über die Hierarchie der `EventListener`-Interfaces.

Abbildung 28.2: Die Hierarchie der EventListener-Interfaces

|  | Jede der Methoden eines Listener-Interfaces enthält als einziges Argument ein Objekt vom zugehörigen Ereignistyp. Alle Methoden sind vom Typ `void`, erzeugen also keinen Rückgabewert. Dies steht in strengem Kontrast zu den Ereignishandlern des AWT 1.0, bei denen der Rückgabewert darüber entschieden hat, ob das Ereignis in der Vererbungshierarchie weiter nach oben gereicht werden sollte oder nicht. Im AWT 1.1 werden Ereignisse dagegen grundsätzlich nicht automatisch weitergereicht. |  |
Hinweis

### 28.1.4 Ereignisquellen

Die Ereignisse stammen von den Ereignisquellen, also von Fenstern, Dialogelementen oder höheren Programmobjekten. Eine Ereignisquelle sendet aber nur dann Ereignisse an einen Ereignisempfänger, wenn dieser sich bei der Ereignisquelle registriert hat. Fehlt eine solche Registrierung, wird die Ereignisquelle keine Ereignisse senden und der Empfänger folglich auch keine erhalten.

Die Registrierung erfolgt mit speziellen Methoden, an die ein Objekt übergeben wird, das das jeweilige `EventListener`-Interface implementiert. So gibt es beispielsweise eine Methode `addMouseListener` in der Klasse `Component`, mit der ein Objekt, das das Interface `MouseListener` implementiert, sich für den Empfang von Mausereignissen bei der Komponente registrieren lassen kann. Nach erfolgter Registrierung wird bei jedem Mausereignis die entsprechende Methode `mouseClicked`, `mouseEntered`, `mouseExited`, `mousePressed` oder `mouseReleased` aufgerufen.

|  | Die Ereignisquellen unterstützen das Multicasting von Ereignissen. Dabei kann eine Ereignisquelle nicht nur einen einzelnen `EventListener` mit Nachrichten versorgen, sondern eine beliebige Anzahl von ihnen. Jeder Aufruf von `addXYZListener` registriert dabei einen weiteren Listener in der Ereignisquelle. Das AWT definiert nicht, in welcher Reihenfolge die verschiedenen Ereignisempfänger beim Auftreten eines Ereignisses aufgerufen werden, und empfiehlt den Programmen, hierüber keine Annahmen zu treffen. |  |
Hinweis

### 28.1.5 Adapterklassen

Eine Adapterklasse in Java ist eine Klasse, die ein vorgegebenes Interface mit leeren Methodenrümpfen implementiert. Adapterklassen können verwendet werden, wenn aus einem Interface lediglich ein Teil der Methoden benötigt wird, der Rest aber uninteressant ist. In diesem Fall leitet man einfach eine neue Klasse aus der Adapterklasse ab, anstatt das zugehörige Interface zu implementieren, und überlagert die benötigten Methoden. Alle übrigen Methoden des Interfaces werden von der Basisklasse zur Verfügung gestellt.

Zu jedem der Low-Level-Ereignisempfänger stellt das Paket `java.awt.event` eine passende Adapterklasse zur Verfügung. So gibt es die Adapterklassen `FocusAdapter`, `KeyAdapter`, `MouseAdapter`, `MouseMotionAdapter`, `ComponentAdapter`, `ContainerAdapter` und `WindowAdapter`. Sie implementieren die korrespondierenden Interfaces. Wir werden später bei der Beschreibung der lokalen und anonymen Klassen sehen, wie die Adapterklassen bei der Realisierung der Ereignisempfänger hilfreich sein können.

### 28.1.6 Zusammenfassung

Der folgende Überblick bündelt die bisherigen Ausführungen und gibt eine Zusammenfassung aller Ereignisse nebst zugehörigen Ereignisempfängern und ihren Methoden. Außerdem sind die Ereignisquellen und die Methoden zur Registrierung der Ereignisse angegeben. Jeder Ereignistyp wird dabei durch zwei Tabellen dargestellt. Die erste gibt die zugehörige Ereignisklasse, das Listener-Interface und den Namen der Methode zur Registrierung von Ereignisempfängern an. Sie listet außerdem die als Ereignisquelle in Frage kommenden Klassen auf. Die zweite Tabelle enthält alle Methoden des zugehörigen Listener-Interfaces und beschreibt damit die zu diesem Ereignistyp gehörenden Elementarereignisse.

|  | Genaugenommen nimmt dieser Abschnitt Informationen vorweg, die in späteren Teilen des Buches konkretisiert werden. Obwohl zum jetzigen Zeitpunkt nicht alle Ereignisse in ihrer vollen Bedeutung dargestellt werden können, mag diese Übersicht für die weitere Arbeit mit dem AWT und zum Nachschlagen hilfreich sein. |  |
Hinweis

#### Focus-Ereignisse

Eigenschaft | Klasse, Interface oder Methode
Ereignisklasse | `FocusEvent`
Listener-Interface | `FocusListener`
Registrierungsmethode | `addFocusListener`
Mögliche Ereignisquellen | `Component`

Tabelle 28.1: Focus-Ereignisse

Ereignismethode | Bedeutung
`focusGained` | Eine Komponente erhält den Focus.
`focusLost` | Eine Komponente verliert den Focus.

Tabelle 28.2: Methoden für Focus-Ereignisse

#### Key-Ereignisse

Eigenschaft | Klasse, Interface oder Methode
Ereignisklasse | `KeyEvent`
Listener-Interface | `KeyListener`
Registrierungsmethode | `addKeyListener`
Mögliche Ereignisquellen | `Component`

Tabelle 28.3: Key-Ereignisse

Ereignismethode | Bedeutung
`keyPressed` | Eine Taste wurde gedrückt.
`keyReleased` | Eine Taste wurde losgelassen.
`keyTyped` | Eine Taste wurde gedrückt und wieder losgelassen.

Tabelle 28.4: Methoden für Key-Ereignisse

#### Mouse-Ereignisse

Eigenschaft | Klasse, Interface oder Methode
Ereignisklasse | `MouseEvent`
Listener-Interface | `MouseListener`
Registrierungsmethode | `addMouseListener`
Mögliche Ereignisquellen | `Component`

Tabelle 28.5: Mouse-Ereignisse

Ereignismethode | Bedeutung
`mouseClicked` | Eine Maustaste wurde gedrückt und wieder losgelassen.
`mouseEntered` | Der Mauszeiger betritt die Komponente.
`mouseExited` | Der Mauszeiger verläßt die Komponente.
`mousePressed` | Eine Maustaste wurde gedrückt.
`mouseReleased` | Eine Maustaste wurde losgelassen.

Tabelle 28.6: Methoden für Mouse-Ereignisse

#### MouseMotion-Ereignisse

Eigenschaft | Klasse, Interface oder Methode
Ereignisklasse | `MouseEvent`
Listener-Interface | `MouseMotionListener`
Registrierungsmethode | `addMouseMotionListener`
Mögliche Ereignisquellen | `Component`

Tabelle 28.7: MouseMotion-Ereignisse

Ereignismethode | Bedeutung
`mouseDragged` | Die Maus wurde bei gedrückter Taste bewegt.
`mouseMoved` | Die Maus wurde bewegt, ohne daß eine Taste gedrückt wurde.

Tabelle 28.8: Methoden für MouseMotion-Ereignisse

#### Component-Ereignisse

Eigenschaft | Klasse, Interface oder Methode
Ereignisklasse | `ComponentEvent`
Listener-Interface | `ComponentListener`
Registrierungsmethode | `addComponentListener`
Mögliche Ereignisquellen | `Component`

Tabelle 28.9: Komponenten-Ereignisse

Ereignismethode | Bedeutung
`componentHidden` | Eine Komponente wurde unsichtbar.
`componentMoved` | Eine Komponente wurde verschoben.
`componentResized` | Die Größe einer Komponente hat sich geändert.
`componentShown` | Eine Komponente wurde sichtbar.

Tabelle 28.10: Methoden für Komponenten-Ereignisse

#### Container-Ereignisse

Eigenschaft | Klasse, Interface oder Methode
Ereignisklasse | `ContainerEvent`
Listener-Interface | `ContainerListener`
Registrierungsmethode | `addContainerListener`
Mögliche Ereignisquellen | `Container`

Tabelle 28.11: Container-Ereignisse

Ereignismethode | Bedeutung
`componentAdded` | Eine Komponente wurde hinzugefügt.
`componentRemoved` | Eine Komponente wurde entfernt.

Tabelle 28.12: Methoden für Container-Ereignisse

#### Window-Ereignisse

Eigenschaft | Klasse, Interface oder Methode
Ereignisklasse | `WindowEvent`
Listener-Interface | `WindowListener`
Registrierungsmethode | `addWindowListener`
Mögliche Ereignisquellen | `Dialog`, `Frame`

Tabelle 28.13: Window-Ereignisse

Ereignismethode | Bedeutung
`windowActivated` | Das Fenster wurde aktiviert.
`windowClosed` | Das Fenster wurde geschlossen.
`windowClosing` | Das Fenster wird geschlossen.
`windowDeactivated` | Das Fenster wurde deaktiviert.
`windowDeiconified` | Das Fenster wurde wiederhergestellt.
`windowIconified` | Das Fenster wurde auf Symbolgröße verkleinert.
`windowOpened` | Das Fenster wurde geöffnet.

Tabelle 28.14: Methoden für Window-Ereignisse

#### Action-Ereignisse

Eigenschaft | Klasse, Interface oder Methode
Ereignisklasse | `ActionEvent`
Listener-Interface | `ActionListener`
Registrierungsmethode | `addActionListener`
Mögliche Ereignisquellen | `Button`, `List`, `MenuItem`, `TextField`

Tabelle 28.15: Action-Ereignisse

Ereignismethode | Bedeutung
`actionPerformed` | Eine Aktion wurde ausgelöst.

Tabelle 28.16: Methoden für Action-Ereignisse

#### Adjustment-Ereignisse

Eigenschaft | Klasse, Interface oder Methode
Ereignisklasse | `AdjustmentEvent`
Listener-Interface | `AdjustmentListener`
Registrierungsmethode | `addAdjustmentListener`
Mögliche Ereignisquellen | `Scrollbar`

Tabelle 28.17: Adjustment-Ereignisse

Ereignismethode | Bedeutung
`adjustmentValueChanged` | Der Wert wurde verändert.

Tabelle 28.18: Methoden für Adjustment-Ereignisse

#### Item-Ereignisse

Eigenschaft | Klasse, Interface oder Methode
Ereignisklasse | `ItemEvent`
Listener-Interface | `ItemListener`
Registrierungsmethode | `addItemListener`
Mögliche Ereignisquellen | `Checkbox`, `Choice`, `List`, `CheckboxMenuItem`

Tabelle 28.19: Item-Ereignisse

Ereignismethode | Bedeutung
`itemStateChanged` | Der Zustand hat sich verändert.

Tabelle 28.20: Methoden für Item-Ereignisse

#### Text-Ereignisse

Eigenschaft | Klasse, Interface oder Methode
Ereignisklasse | `TextEvent`
Listener-Interface | `TextListener`
Registrierungsmethode | `addTextListener`
Mögliche Ereignisquellen | `TextField`, `TextArea`

Tabelle 28.21: Text-Ereignisse

Ereignismethode | Bedeutung
`textValueChanged` | Der Text wurde verändert.

Tabelle 28.22: Methoden für Text-Ereignisse

Titel | Inhalt | Suchen | Index | DOC | Handbuch der Java-Programmierung, 3. Auflage, Addison Wesley, Version 3.0
<< | < | > | >> | API | © 1998-2002 Guido Krüger, http://www.javabuch.de