Java e gestione degli eventi

La maggior parte dei programmi, per essere utili, devono rispondere ai comandi dell'utente. A tale scopo, i programmi Java si basano su eventi che descrivono le azioni dell'utente.

Il mese scorso ho dimostrato come assemblare un'interfaccia utente grafica dai componenti forniti dal toolkit di finestre astratte della libreria di classi Java. Dopo aver assemblato alcune di queste interfacce, ho parlato brevemente dell'argomento della gestione degli eventi, ma mi sono fermato prima di una descrizione completa della gestione degli eventi implementata dall'AWT. Questo mese riprendiamo da dove avevamo interrotto.

Essere guidato dagli eventi

In un lontano passato, un programma che voleva sapere cosa stava facendo l'utente doveva raccogliere attivamente tali informazioni da solo. In pratica questo significava che dopo che un programma si era inizializzato, entrava in un grande loop in cui cercava ripetutamente se l'utente stesse facendo qualcosa di interessante (ad esempio, premendo un pulsante, toccando un tasto, spostando un cursore, spostando il mouse) e quindi ha intrapreso l'azione appropriata. Questa tecnica è nota come polling .

Il polling porta a termine il lavoro, ma tende ad essere ingombrante se utilizzato nelle applicazioni moderne per due ragioni correlate: primo, l'uso del polling tende a spingere tutto il codice di gestione degli eventi in una posizione (all'interno del big loop); secondo, le interazioni risultanti all'interno del big loop tendono ad essere complesse. Inoltre, il polling richiede che un programma si trovi in ​​un ciclo, consumando cicli della CPU, mentre attende che l'utente faccia qualcosa: un serio spreco di una risorsa preziosa.

L'AWT ha risolto questi problemi abbracciando un paradigma diverso, che è alla base di tutti i moderni sistemi a finestre: la programmazione guidata dagli eventi. All'interno dell'AWT, tutte le azioni dell'utente appartengono a un insieme astratto di cose chiamate eventi . Un evento descrive, in modo sufficientemente dettagliato, una particolare azione dell'utente. Piuttosto che il programma che raccoglie attivamente eventi generati dall'utente, il runtime Java notifica al programma quando si verifica un evento interessante. Si dice che i programmi che gestiscono l'interazione dell'utente in questo modo siano guidati dagli eventi .

La classe Event

La classe Event è il giocatore principale nel gioco degli eventi. Tenta di catturare le caratteristiche fondamentali di tutti gli eventi generati dagli utenti. La tabella 1 elenca i membri dei dati pubblici forniti dalla classe Event.

genere Nome Descrizione
Oggetto bersaglio Un riferimento al componente che ha inizialmente ricevuto l'evento.
lungo quando Il momento in cui si è verificato l'evento.
int id Il tipo di evento (vedere la sezione Tipi di evento per ulteriori informazioni).
int X La coordinata x in corrispondenza della quale si è verificata l'azione rispetto al componente che sta attualmente elaborando l'evento. Per un dato evento, la coordinata x cambierà di valore quando l'evento si sposta verso l'alto nella gerarchia dei componenti. L'origine del piano delle coordinate si trova nell'angolo superiore sinistro del componente.
int y La coordinata y in corrispondenza della quale si è verificata l'azione rispetto al componente che sta attualmente elaborando l'evento. Per un dato evento, la coordinata y cambierà di valore quando l'evento si sposta verso l'alto nella gerarchia dei componenti. L'origine del piano delle coordinate si trova nell'angolo superiore sinistro del componente.
int chiave Per gli eventi da tastiera, il codice del tasto appena premuto. Il suo valore sarà in genere il valore Unicode del carattere rappresentato dalla chiave. Altre possibilità includono valori per i tasti speciali HOME, END, F1, F2 e così via.
int modificatori Una combinazione aritmetica o di valori SHIFT_MASK, CTRL_MASK, META_MASK e ALT_MASK. Il suo valore rappresenta rispettivamente lo stato dei tasti shift, control, meta e alt.
int clickCount Il numero di clic del mouse consecutivi. Questo membro dati è significativo solo negli eventi MOUSE_DOWN.
Oggetto arg Un argomento dipendente dall'evento. Per gli oggetti Button, questo oggetto è un oggetto String che contiene l'etichetta materica del pulsante.
Tabella 1: membri di dati pubblici forniti dalla classe Event

Come spiegherò nella sezione intitolata Spedizione e propagazione degli eventi , un'istanza della classe Event viene tipicamente creata dal sistema run-time Java. È possibile, tuttavia, che un programma crei e invii eventi ai componenti tramite il loro postEvent()metodo.

Tipi di eventi

Come accennato in precedenza, la classe Event è un modello di un evento dell'interfaccia utente. Gli eventi rientrano naturalmente in categorie in base al tipo di evento (il tipo di evento è indicato dal idmembro dei dati). La tabella 2 elenca tutti gli eventi definiti dall'AWT, ordinati per categoria.

Tabella 2: eventi definiti dall'AWT, ordinati per categoria

Può essere istruttivo vedere la generazione di eventi in azione. Il pulsante nella Figura 1, se premuto, crea un browser degli eventi che visualizza le informazioni sugli eventi sugli eventi ricevuti dal browser. Il codice sorgente per il browser degli eventi è disponibile qui.

È necessario un browser abilitato per Java per visualizzare questa applet

Figura 1: generazione di eventi in azione

Invio e propagazione di eventi

Considera l'applet nella Figura 2. Consiste di due istanze della classe Button, incorporate in un'istanza della classe Panel. Questa istanza della classe Panel è essa stessa incorporata in un'altra istanza della classe Panel. L'ultima istanza della classe Panel si trova sotto un'istanza della classe TextArea ed entrambe le istanze sono incorporate in un'istanza della classe Applet. La Figura 3 presenta gli elementi che compongono questa applet disposti come un albero, con le istanze TextArea e Button come foglie e un'istanza dell'applet come radice. (Per ulteriori informazioni sul layout gerarchico dei componenti in un'interfaccia utente, leggi l'introduzione del mese scorso all'AWT.)

È necessario un browser abilitato per Java per visualizzare questa applet

Figura 2: classi incorporate nelle classi

Figura 3: albero degli elementi dell'applet (gerarchia)

Quando un utente interagisce con l'applet nella Figura 2, il sistema run-time Java crea un'istanza della classe Event e riempie i suoi membri dati con le informazioni che descrivono l'azione. Il sistema run-time Java consente quindi all'applet di gestire l'evento. Inizia con il componente che ha ricevuto inizialmente l'evento (ad esempio, il pulsante su cui è stato fatto clic) e si sposta verso l'alto nell'albero dei componenti, componente per componente, fino a raggiungere il contenitore in cima all'albero. Lungo il percorso, ogni componente ha la possibilità di ignorare l'evento o di reagire in uno (o più) dei seguenti modi:

  • Modificare i membri di dati dell'istanza di Event
  • Agisci ed esegui alcuni calcoli in base alle informazioni contenute nell'evento
  • Indicare al sistema run-time Java che l'evento non dovrebbe propagarsi più in alto nell'albero

Il sistema run-time Java passa le informazioni sugli eventi a un componente tramite il handleEvent()metodo del componente . Tutti i handleEvent()metodi validi devono essere nel formato

public boolean handleEvent (Event e) 

Un gestore di eventi richiede una singola informazione: un riferimento all'istanza della classe Event contenente informazioni sull'evento che si è appena verificato.

Il valore restituito dal handleEvent()metodo è importante. Indica al sistema run-time Java se l'evento è stato completamente gestito o meno all'interno del gestore eventi. Un valore vero indica che l'evento è stato gestito e la propagazione dovrebbe interrompersi. Un valore falso indica che l'evento è stato ignorato, non può essere gestito o è stato gestito in modo incompleto e deve continuare a risalire l'albero.

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 ha programmato da quando i computer sono diventati disponibili nei modelli desktop. Sebbene inizialmente interessato alla creazione di applicazioni a oggetti distribuiti in C ++, Todd è passato al linguaggio di programmazione Java quando Java è diventato una scelta ovvia per quel genere di cose. Oltre a scrivere, Todd fornisce servizi di consulenza per applicazioni Web e Internet ad aziende negli Stati Uniti sudorientali.

Ulteriori informazioni su questo argomento

  • The Java Tutorial di Mary Campione e Kathy Walrath. La versione bozza in linea è disponibile su //java.sun.com/tutorial/index.html.

Questa storia, "Java e gestione degli eventi" è stata originariamente pubblicata da JavaWorld.