De fleste programmer, for at være nyttige, skal svare på kommandoer fra brugeren. For at gøre dette afhænger Java-programmer af begivenheder, der beskriver brugerhandlinger.
Sidste måned demonstrerede jeg, hvordan jeg samler en grafisk brugergrænseflade fra komponenter leveret af Java-klassebibliotekets abstrakte vinduesværktøjssæt. Efter at have samlet et par sådanne grænseflader talte jeg kort om emnet håndtering af begivenheder, men jeg stoppede kort med en fuld beskrivelse af begivenhedshåndtering som implementeret af AWT. Denne måned fortsætter vi, hvor vi slap.
At være begivenhedsdrevet
I den fjerne fortid var et program, der ønskede at vide, hvad brugeren gjorde, aktivt at indsamle sådanne oplysninger selv. I praksis betød dette, at efter at et program var initialiseret, gik det ind i en stor sløjfe, hvor det gentagne gange kiggede for at se, om brugeren gjorde noget interessant (for eksempel ved at trykke på en knap, røre ved en tast, flytte en skyder, flytte musen) og tog derefter den passende handling. Denne teknik er kendt som afstemning.
Polling får jobbet gjort, men har tendens til at være uhåndterligt, når det bruges i moderne applikationer af to relaterede grunde: For det første har brugen af polling tendens til at skubbe al hændelseshåndteringskode til et sted (inde i den store sløjfe); for det andet har de resulterende interaktioner inden for den store sløjfe tendens til at være komplekse. Derudover kræver afstemning et program til at sidde i en løkke og forbruge CPU-cyklusser, mens de venter på, at brugeren skal gøre noget - et alvorligt spild af en værdifuld ressource.
AWT løste disse problemer ved at omfavne et andet paradigme, der ligger til grund for alle moderne vinduessystemer: begivenhedsdrevet programmering. Inden for AWT hører alle brugerhandlinger til et abstrakt sæt af ting, der kaldes begivenheder. En begivenhed beskriver i tilstrækkelig detaljering en bestemt brugerhandling. I stedet for at programmet aktivt indsamler brugergenererede begivenheder, underrettes Java-kørselstiden for programmet, når der opstår en interessant begivenhed. Programmer der håndterer brugerinteraktion på denne måde siges at være det Hændelsesdrevet.
Begivenhedsklassen
Begivenhedsklassen er den primære spiller i begivenhedsspillet. Det forsøger at fange de grundlæggende egenskaber ved alle brugergenererede begivenheder. tabel 1 viser de offentlige datamedlemmer leveret af klasse Event.
Type | Navn | Beskrivelse |
Objekt | mål | En henvisning til den komponent, der oprindeligt modtog begivenheden. |
lang | hvornår | Det tidspunkt, hvor begivenheden fandt sted. |
int | id | Hændelsestypen (se afsnittet Hændelsestyper for mere information). |
int | x | Den x-koordinat, som handlingen fandt sted i forhold til den komponent, der i øjeblikket behandler begivenheden. For en given begivenhed ændres x-koordinaten i værdi, når begivenheden bevæger sig op ad komponenthierarkiet. Koordinatplanets oprindelse er i komponentens øverste venstre hjørne. |
int | y | Y-koordinaten, som handlingen skete i forhold til den komponent, der i øjeblikket behandler begivenheden. For en given begivenhed ændres y-koordinaten i værdi, når begivenheden bevæger sig op ad komponenthierarkiet. Koordinatplanets oprindelse er i komponentens øverste venstre hjørne. |
int | nøgle | Ved tastaturbegivenheder trykkede tastens nøglekode bare. Dens værdi vil typisk være Unicode-værdien for det tegn, nøglen repræsenterer. Andre muligheder inkluderer værdier for specialtasterne HOME, END, F1, F2 osv. |
int | modifikatorer | En aritmetisk eller ønsket kombination af værdierne SHIFT_MASK, CTRL_MASK, META_MASK og ALT_MASK. Dens værdi repræsenterer henholdsvis skift-, kontrol-, meta- og alt-tasterne. |
int | clickCount | Antallet af på hinanden følgende museklik. Dette datamedlem er kun signifikant i MOUSE_DOWN begivenheder. |
Objekt | arg | Et hændelsesafhængigt argument. For knapobjekter er dette objekt et strengobjekt, der indeholder knapens tekstmærkat. |
Som jeg vil forklare i afsnittet med titlen Forsendelse og formidling af begivenheder, oprettes en forekomst af klassehændelse typisk af Java-kørselssystemet. Det er dog muligt for et program at oprette og sende begivenheder til komponenter via deres postEvent ()
metode.
Begivenhedstyper
Som nævnt ovenfor er begivenhedsklassen en model for en begivenhed i brugergrænsefladen. Begivenheder falder naturligvis i kategorier baseret på typen af begivenheden (begivenhedstypen er angivet med id
data-medlem). Tabel 2 viser alle de begivenheder, der er defineret af AWT, sorteret efter kategori.
Det kan være lærerigt at se begivenhedsgenerering i aktion. Når der trykkes på knappen i figur 1, oprettes en begivenhedsbrowser, der viser begivenhedsoplysninger om de begivenheder, browseren modtager. Kildekoden til begivenhedsbrowseren er tilgængelig her.
Du har brug for en Java-aktiveret browser for at se denne appletFigur 1: Begivenhedsgenerering i aktion
Forsendelse og udbredelse af begivenheder
Overvej appleten i figur 2. Den består af to forekomster af Button-klassen, indlejret i en instans af Panel-klassen. Denne forekomst af Panel-klassen er i sig selv indlejret i en anden forekomst af Panel-klassen. Den sidstnævnte forekomst af Panel-klassen sidder under en forekomst af klasse TextArea, og begge forekomster er indlejret i en forekomst af Applet-klassen. Figur 3 viser de elementer, der udgør denne applet, der er lagt ud som et træ, med forekomsterne TextArea og Button som bladene og en Applet-instans som roden. (For mere information om det hierarkiske layout af komponenter i en brugergrænseflade, læs sidste måneds introduktion til AWT.)
Du har brug for en Java-aktiveret browser for at se denne appletFigur 2: Klasser indlejret i klasser
Figur 3: Træ for appletelementer (hierarki)
Når en bruger interagerer med appleten i figur 2, opretter Java-runtime-systemet en forekomst af klassehændelse og udfylder sine datamedlemmer med information, der beskriver handlingen. Java-run-time-systemet tillader derefter appleten at håndtere begivenheden. Det begynder med den komponent, der oprindeligt modtog begivenheden (for eksempel knappen, der blev klikket på) og bevæger sig op ad komponenttræet, komponent for komponent, indtil den når containeren øverst i træet. Undervejs har hver komponent mulighed for at ignorere begivenheden eller reagere på den på en (eller flere) af følgende måder:
- Rediger datamedlemmerne til begivenhedsinstansen
- Gør handling og udfør nogle beregninger baseret på oplysningerne i begivenheden
- Angiv for Java-runtime-systemet, at begivenheden ikke skal spredes længere op ad træet
Java-kørselssystemet videregiver hændelsesinformation til en komponent via komponentens handleEvent ()
metode. Alle gyldige handleEvent ()
metoder skal være af formen
public boolean handleEvent (begivenhed e)
En begivenhedshåndterer kræver et enkelt stykke information: en henvisning til forekomsten af begivenhedsklassen, der indeholder oplysninger om den begivenhed, der netop fandt sted.
Værdien returneret fra handleEvent ()
metoden er vigtig. Det angiver over for Java-kørselssystemet, om begivenheden er blevet håndteret fuldstændigt inden for begivenhedshåndteringen. En ægte værdi indikerer, at begivenheden er håndteret, og udbredelsen skal stoppe. En falsk værdi indikerer, at begivenheden er ignoreret, ikke kunne håndteres eller er blevet håndteret ufuldstændigt og skal fortsætte op ad træet.
Overvej følgende beskrivelse af en imaginær brugers interaktion med appleten i figur 2. Brugeren klikker på knappen mærket "One". Java-sprogets run-time-system indsamler oplysninger om begivenheden (antallet af klik, placeringen af kliket, tidspunktet for klik, og den komponent, der modtog kliket) og pakker disse oplysninger i en forekomst af begivenhedsklassen. Java-run-time-systemet begynder derefter ved den komponent, der blev klikket på (i dette tilfælde knappen mærket "One") og via et opkald til komponentens handleEvent ()
metode, giver komponenten en chance for at reagere på begivenheden. Hvis komponenten ikke håndterer begivenheden eller håndterer begivenheden ufuldstændigt (angivet med en returværdi på falsk), tilbyder Java-kørselstidssystemet Begivenhedsforekomsten til den næste højere komponent i træet - i dette tilfælde en forekomst af Panel klasse. Java-kørselssystemet fortsætter på denne måde, indtil begivenheden håndteres, eller kørselstidssystemet løber tør for komponenter for at prøve. Figur 4 illustrerer stien til denne begivenhed, når appleten forsøger at håndtere den.
Figur 4: Stien til en begivenhed
Hver komponent, der udgør appleten i figur 2, tilføjer en linje til TextArea-objektet, der angiver, at den har modtaget en begivenhed. Derefter tillader begivenheden at sprede sig til den næste komponent i træet. Liste 1 indeholder koden til en typisk handleEvent ()
metode. Den komplette kildekode til denne applet er tilgængelig her.
public boolean handleEvent (Event evt) {if (evt.id == Event.ACTION_EVENT) {ta.appendText ("Panel" + str + "saw action ... \ n"); } ellers hvis (evt.id == Event.MOUSE_DOWN) {ta.appendText ("Panel" + str + "så musen ned ... \ n"); }
returner super.handleEvent (evt); }
Liste 1: En typisk handleEvent ()
metode
Metoder til begivenhedshjælper
Det handleEvent ()
metoden er et sted, som en programmør kan placere applikationskode til håndtering af begivenheder. Lejlighedsvis vil en komponent dog kun være interesseret i begivenheder af en bestemt type (for eksempel musebegivenheder). I disse tilfælde kan programmøren placere koden i en hjælper metode, snarere end at placere det i handleEvent ()
metode.
Her er en liste over de hjælpemetoder, der er tilgængelige for programmører. Der er ingen hjælpemetoder til visse typer begivenheder.
handling (Event evt, Object what)
gotFocus (Event evt, Object what)
lostFocus (Event evt, Object what)
mouseEnter (begivenhed evt, int x, int y)
mouseExit (begivenhed evt, int x, int y)
mouseMove (begivenhed evt, int x, int y)
mouseUp (begivenhed evt, int x, int y)
mouseDown (begivenhed evt, int x, int y)
mouseDrag (begivenhed evt, int x, int y)
keyDown (begivenhed evt, int nøgle)
keyUp (begivenhed evt, int nøgle)
falsk for at indikere, at hjælpemetoden ikke håndterede begivenheden.
Gennemførelsen af handleEvent ()
metode leveret af klasse Komponent påberåber hver hjælpermetode. Af denne grund er det vigtigt, at de omdefinerede implementeringer af handleEvent ()
metode i afledte klasser slutter altid med udsagnet
returner super.handleEvent (e);
Koden i liste 2 illustrerer denne regel.
public boolean handleEvent (Event e) {if (e.target instanceof MyButton) {// gør noget ... returner sandt; }
returner super.handleEvent (e); }
Liste 2: Regel for afslutning af udsagn i handleEvent ()
metode
Manglende overholdelse af denne enkle regel forhindrer korrekt påkaldelse af hjælpemetoder.
Figur 5 indeholder en applet, der udelukkende håndterer musebegivenheder gennem kode placeret i hjælpemetoder. Kildekoden er tilgængelig her.
Begivenhed | evt | Den næste begivenhed på en sammenkædet liste over begivenheder. |
Vinduesbegivenheder | ||
Vinduehændelser genereres som reaktion på ændringer i tilstanden for et vindue, en ramme eller en dialog. | ||
Begivenhed | ID | |
WINDOW_DESTROY | 201 | |
WINDOW_EXPOSE | 202 | |
WINDOW_ICONIFY | 203 | |
WINDOW_DEICONIFY | 204 | |
WINDOW_MOVED | 205 | |
Tastaturbegivenheder | ||
Tastaturhændelser genereres som reaktion på taster, der trykkes og frigives, mens en komponent har inputfokus. | ||
Begivenhed | ID | |
TASTETRYK | 401 | |
KEY_RELEASE | 402 | |
KEY_ACTION | 403 | |
KEY_ACTION_RELEASE | 404 | |
Musbegivenheder | ||
Mushændelser genereres som svar på mushandlinger, der forekommer inden for en komponents grænser. | ||
Begivenhed | ID | |
MOUSE_DOWN | 501 | |
MOUSE_UP | 502 | |
MOUSE_MOVE | 503 | |
MOUSE_ENTER | 504 | |
MOUSE_EXIT | 505 | |
MUSE_DRAG | 506 | |
Rul begivenheder | ||
Rullehændelser genereres som reaktion på manipulation af rullebjælker. | ||
Begivenhed | ID | |
SCROLL_LINE_UP | 601 | |
SCROLL_LINE_DOWN | 602 | |
SCROLL_PAGE_UP | 603 | |
SCROLL_PAGE_DOWN | 604 | |
SCROLL_ABSOLUTE | 605 | |
Liste begivenheder | ||
Listehændelser genereres som svar på valg foretaget på en liste. | ||
Begivenhed | ID | |
LIST_SELECT | 701 | |
LIST_DESELECT | 702 | |
Diverse begivenheder | ||
Diverse begivenheder genereres som reaktion på en række handlinger. | ||
Begivenhed | ID | |
ACTION_EVENT | 1001 | |
LOAD_FILE | 1002 | |
GEM FILEN | 1003 | |
GOT_FOCUS | 1004 | |
LOST_FOCUS | 1005 |
Lær mere om dette emne
- Java-vejledningen af Mary Campione og Kathy Walrath. Onlineudkastversionen er tilgængelig på //java.sun.com/tutorial/index.html.
Denne historie, "Java and event handling" blev oprindeligt udgivet af JavaWorld.