Java und Ereignisbehandlung

Die meisten Programme müssen auf Befehle des Benutzers reagieren, um nützlich zu sein. Zu diesem Zweck stützen sich Java-Programme auf Ereignisse, die Benutzeraktionen beschreiben.

Letzten Monat habe ich gezeigt, wie eine grafische Benutzeroberfläche aus Komponenten zusammengesetzt wird, die vom Toolkit für abstrakte Fenster der Java-Klassenbibliothek bereitgestellt werden. Nachdem ich einige solcher Schnittstellen zusammengestellt hatte, sprach ich kurz über das Thema Ereignisbehandlung, hielt jedoch an einer vollständigen Beschreibung der Ereignisbehandlung fest, wie sie von der AWT implementiert wurde. Diesen Monat machen wir dort weiter, wo wir aufgehört haben.

Ereignisorientiert sein

In der fernen Vergangenheit musste ein Programm, das wissen wollte, was der Benutzer tat, solche Informationen selbst aktiv sammeln. In der Praxis bedeutete dies, dass ein Programm, nachdem es sich selbst initialisiert hatte, in eine große Schleife eintrat, in der wiederholt geprüft wurde, ob der Benutzer etwas Interessantes tat (z. B. Drücken einer Taste, Berühren einer Taste, Bewegen eines Schiebereglers, Bewegen der Maus). und ergriff dann die entsprechenden Maßnahmen. Diese Technik wird als Polling bezeichnet .

Polling erledigt die Aufgabe, ist jedoch in modernen Anwendungen aus zwei Gründen unhandlich: Erstens wird durch die Verwendung von Polling der gesamte Code für die Ereignisbehandlung an einen Ort (innerhalb der großen Schleife) verschoben. Zweitens sind die resultierenden Wechselwirkungen innerhalb der großen Schleife tendenziell komplex. Darüber hinaus erfordert das Abrufen, dass ein Programm in einer Schleife sitzt, CPU-Zyklen verbraucht und darauf wartet, dass der Benutzer etwas unternimmt - eine ernsthafte Verschwendung einer wertvollen Ressource.

Das AWT löste diese Probleme, indem es ein anderes Paradigma übernahm, das allen modernen Fenstersystemen zugrunde liegt: ereignisgesteuerte Programmierung. Innerhalb der AWT gehören alle Benutzeraktionen zu einer abstrakten Gruppe von Dingen, die als Ereignisse bezeichnet werden . Ein Ereignis beschreibt eine bestimmte Benutzeraktion ausreichend detailliert. Anstatt dass das Programm vom Benutzer generierte Ereignisse aktiv sammelt, benachrichtigt die Java-Laufzeit das Programm, wenn ein interessantes Ereignis auftritt. Programme, die die Benutzerinteraktion auf diese Weise handhaben, werden als ereignisgesteuert bezeichnet .

Die Ereignisklasse

Die Event-Klasse ist der primäre Spieler im Event-Spiel. Es wird versucht, die grundlegenden Merkmale aller vom Benutzer generierten Ereignisse zu erfassen. In Tabelle 1 sind die öffentlichen Datenelemente aufgeführt, die von der Klasse Event bereitgestellt werden.

Art Name Beschreibung
Objekt Ziel Ein Verweis auf die Komponente, die das Ereignis ursprünglich empfangen hat.
lange wann Der Zeitpunkt, zu dem das Ereignis aufgetreten ist.
int Ich würde Der Ereignistyp (weitere Informationen finden Sie im Abschnitt Ereignistypen).
int x Die x-Koordinate, an der die Aktion relativ zu der Komponente ausgeführt wurde, die das Ereignis gerade verarbeitet. Für ein bestimmtes Ereignis ändert sich der Wert der x-Koordinate, wenn das Ereignis die Komponentenhierarchie nach oben bewegt. Der Ursprung der Koordinatenebene liegt in der oberen linken Ecke der Komponente.
int y Die y-Koordinate, an der die Aktion relativ zu der Komponente ausgeführt wurde, die das Ereignis gerade verarbeitet. Für ein bestimmtes Ereignis ändert sich der Wert der y-Koordinate, wenn das Ereignis die Komponentenhierarchie nach oben bewegt. Der Ursprung der Koordinatenebene liegt in der oberen linken Ecke der Komponente.
int Schlüssel Bei Tastaturereignissen der Tastencode der gerade gedrückten Taste. Sein Wert ist normalerweise der Unicode-Wert des Zeichens, das der Schlüssel darstellt. Weitere Möglichkeiten sind Werte für die Sondertasten HOME, END, F1, F2 usw.
int Modifikatoren Eine arithmetische oder Kombination der Werte SHIFT_MASK, CTRL_MASK, META_MASK und ALT_MASK. Sein Wert repräsentiert den Status der Shift-, Control-, Meta- und Alt-Tasten.
int clickCount Die Anzahl aufeinanderfolgender Mausklicks. Dieses Datenelement ist nur in MOUSE_DOWN-Ereignissen von Bedeutung.
Objekt arg Ein ereignisabhängiges Argument. Bei Schaltflächenobjekten ist dieses Objekt ein Zeichenfolgenobjekt, das die Texturbezeichnung der Schaltfläche enthält.
Tabelle 1: Öffentliche Datenelemente, die von der Klasse Event bereitgestellt werden

Wie ich im Abschnitt " Ereignisversand und -weitergabe" erläutern werde , wird eine Instanz der Klasse "Ereignis" normalerweise vom Java-Laufzeitsystem erstellt. Es ist jedoch möglich, dass ein Programm Ereignisse über ihre postEvent()Methode erstellt und an Komponenten sendet .

Ereignistypen

Wie oben erwähnt, ist die Ereignisklasse ein Modell eines Benutzeroberflächenereignisses. Ereignisse fallen natürlich in Kategorien, die auf dem Typ des Ereignisses basieren (der Ereignistyp wird vom idDatenelement angegeben). In Tabelle 2 sind alle von der AWT definierten Ereignisse nach Kategorien sortiert aufgeführt.

Tabelle 2: Vom AWT definierte Ereignisse, sortiert nach Kategorien

Es kann lehrreich sein, die Ereignisgenerierung in Aktion zu sehen. Wenn die Schaltfläche in Abbildung 1 gedrückt wird, wird ein Ereignisbrowser erstellt, der Ereignisinformationen zu den Ereignissen anzeigt, die der Browser empfängt. Den Quellcode für den Ereignisbrowser finden Sie hier.

Sie benötigen einen Java-fähigen Browser, um dieses Applet anzuzeigen

Abbildung 1: Ereignisgenerierung in Aktion

Ereignisversand und -weitergabe

Betrachten Sie das Applet in Abbildung 2. Es besteht aus zwei Instanzen der Button-Klasse, die in eine Instanz der Panel-Klasse eingebettet sind. Diese Instanz der Panel-Klasse ist selbst in eine andere Instanz der Panel-Klasse eingebettet. Die letztere Instanz der Panel-Klasse befindet sich unter einer Instanz der Klasse TextArea, und beide Instanzen sind in eine Instanz der Applet-Klasse eingebettet. In Abbildung 3 sind die Elemente dargestellt, aus denen dieses Applet besteht, das als Baum angeordnet ist, wobei die Instanzen TextArea und Button als Blätter und eine Applet-Instanz als Stamm verwendet werden. (Weitere Informationen zum hierarchischen Layout von Komponenten in einer Benutzeroberfläche finden Sie in der Einführung zum AWT im letzten Monat.)

Sie benötigen einen Java-fähigen Browser, um dieses Applet anzuzeigen

Abbildung 2: In Klassen eingebettete Klassen

Abbildung 3: Applet-Elementbaum (Hierarchie)

Wenn ein Benutzer mit dem Applet in Abbildung 2 interagiert, erstellt das Java-Laufzeitsystem eine Instanz der Klasse Event und füllt seine Datenelemente mit Informationen, die die Aktion beschreiben. Das Java-Laufzeitsystem ermöglicht es dem Applet dann, das Ereignis zu behandeln. Es beginnt mit der Komponente, die das Ereignis ursprünglich empfangen hat (z. B. die Schaltfläche, auf die geklickt wurde), und verschiebt den Komponentenbaum Komponente für Komponente nach oben, bis es den Container oben im Baum erreicht. Unterwegs hat jede Komponente die Möglichkeit, das Ereignis zu ignorieren oder auf eine (oder mehrere) der folgenden Arten darauf zu reagieren:

  • Ändern Sie die Datenelemente der Ereignisinstanz
  • Ergreifen Sie Maßnahmen und führen Sie einige Berechnungen basierend auf den im Ereignis enthaltenen Informationen durch
  • Geben Sie dem Java-Laufzeitsystem an, dass sich das Ereignis nicht weiter im Baum ausbreiten soll

Das Java-Laufzeitsystem übergibt Ereignisinformationen über die handleEvent()Methode der Komponente an eine Komponente . Alle gültigen handleEvent()Methoden müssen die Form haben

public boolean handleEvent (Ereignis e) 

Ein Ereignishandler benötigt eine einzelne Information: einen Verweis auf die Instanz der Ereignisklasse, die Informationen zu dem gerade aufgetretenen Ereignis enthält.

Der von der handleEvent()Methode zurückgegebene Wert ist wichtig. Es zeigt dem Java-Laufzeitsystem an, ob das Ereignis vollständig im Ereignishandler behandelt wurde oder nicht. Ein wahrer Wert gibt an, dass das Ereignis behandelt wurde und die Weitergabe gestoppt werden sollte. Ein falscher Wert zeigt an, dass das Ereignis ignoriert wurde, nicht behandelt werden konnte oder unvollständig behandelt wurde und im Baum fortgesetzt werden sollte.

Consider the following description of an imaginary user's interaction with the applet in Figure 2. The user clicks on the button labeled "One." The Java language run-time system gathers information about the event (the number of clicks, the location of the click, the time the click occurred, and the component that received the click) and packages that information in an instance of the Event class. The Java run-time system then begins at the component that was clicked (in this case, the Button labeled "One") and, via a call to the component's handleEvent() method, offers the component a chance to react to the event. If the component does not handle the event or handles the event incompletely (indicated by a return value of false), the Java run-time system offers the Event instance to the next higher component in the tree -- in this case an instance of the Panel class. The Java run-time system continues in this manner until the event is handled or the run-time system runs out of components to try. Figure 4 illustrates the path of this event as the applet attempts to handle it.

Figure 4: The path of an event

Each component making up the applet in Figure 2 adds a line to the TextArea object that indicates it received an event. It then allows the event to propagate to the next component in the tree. Listing 1 contains the code for a typical handleEvent() method. The complete source code for this applet is available here.

public boolean handleEvent(Event evt) { if (evt.id == Event.ACTION_EVENT) { ta.appendText("Panel " + str + " saw action...\n"); } else if (evt.id == Event.MOUSE_DOWN) { ta.appendText("Panel " + str + " saw mouse down...\n"); }

return super.handleEvent(evt); }

Listing 1: A typical handleEvent() method

Event helper methods

The handleEvent() method is one place a programmer can put application code for handling events. Occasionally, however, a component will only be interested in events of a certain type (for example, mouse events). In these cases, the programmer can place the code in a helper method, rather than placing it in the handleEvent() method.

Here is a list of the helper methods available to programmers. There are no helper methods for certain types of events.

action(Event evt, Object what)

gotFocus(Event evt, Object what)

lostFocus(Event evt, Object what)

mouseEnter(Event evt, int x, int y)

mouseExit(Event evt, int x, int y)

mouseMove(Event evt, int x, int y)

mouseUp(Event evt, int x, int y)

mouseDown(Event evt, int x, int y)

mouseDrag(Event evt, int x, int y)

keyDown(Event evt, int key)

keyUp(Event evt, int key)

false to indicate that the helper method did not handle the event.

The implementation of the handleEvent() method provided by class Component invokes each helper method. For this reason, it is important that the redefined implementations of the handleEvent() method in derived classes always end with the statement

return super.handleEvent(e);

The code in Listing 2 illustrates this rule.

public boolean handleEvent(Event e) { if (e.target instanceof MyButton) { // do something... return true; }

return super.handleEvent(e); }

Listing 2: Rule for ending statement in handleEvent() method

Failure to follow this simple rule will prevent the proper invocation of helper methods.

Figure 5 contains an applet that handles mouse events solely through code placed in helper methods. The source code is available here.

Event evt The next event in a linked list of events.
Window events
Window events are generated in response to changes in the state of a window, frame, or dialog.
Event ID
WINDOW_DESTROY 201
WINDOW_EXPOSE 202
WINDOW_ICONIFY 203
WINDOW_DEICONIFY 204
WINDOW_MOVED 205
Keyboard events
Keyboard events are generated in response to keys pressed and released while a component has input focus.
Event ID
KEY_PRESS 401
KEY_RELEASE 402
KEY_ACTION 403
KEY_ACTION_RELEASE 404
Mouse events
Mouse events are generated in response to mouse actions occurring within the boundary of a component.
Event ID
MOUSE_DOWN 501
MOUSE_UP 502
MOUSE_MOVE 503
MOUSE_ENTER 504
MOUSE_EXIT 505
MOUSE_DRAG 506
Scroll events
Scroll events are generated in response to manipulation of scrollbars.
Event ID
SCROLL_LINE_UP 601
SCROLL_LINE_DOWN 602
SCROLL_PAGE_UP 603
SCROLL_PAGE_DOWN 604
SCROLL_ABSOLUTE 605
List events
List events are generated in response to selections made to a list.
Event ID
LIST_SELECT 701
LIST_DESELECT 702
Miscellaneous events
Miscellaneous events are generated in response to a variety of actions.
Event ID
ACTION_EVENT 1001
LOAD_FILE 1002
SAVE_FILE 1003
GOT_FOCUS 1004
LOST_FOCUS 1005
Todd Sundsted programmiert seit Computer in Desktop-Modellen verfügbar sind. Obwohl Todd ursprünglich daran interessiert war, verteilte Objektanwendungen in C ++ zu erstellen, wechselte er zur Java-Programmiersprache, als Java eine offensichtliche Wahl für solche Dinge wurde. Neben dem Schreiben bietet Todd Unternehmen im Südosten der USA Beratungsdienste für Internet- und Webanwendungen an.

Erfahren Sie mehr über dieses Thema

  • Das Java Tutorial von Mary Campione und Kathy Walrath. Die Online-Entwurfsversion ist unter //java.sun.com/tutorial/index.html verfügbar.

Diese Geschichte "Java und Ereignisbehandlung" wurde ursprünglich von JavaWorld veröffentlicht.