Titel | Inhalt | Suchen | Index | API | Go To Java 2, Zweite Auflage, Handbuch der Java-Programmierung |
<< | < | > | >> | Kapitel 28 - Event-Handling |
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:
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:
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. |
|
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: |
|
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. |
|
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. |
|
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. |
|
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.
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. |
|
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
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
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
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
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
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
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
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
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
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
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 | API | Go To Java 2, Zweite Auflage, Addison Wesley, Version 2.0 |
<< | < | > | >> | © 2000 Guido Krüger, http://www.gkrueger.com |