De fleste programmer, for å være nyttige, må svare på kommandoer fra brukeren. For å gjøre dette stoler Java-programmer på hendelser som beskriver brukerhandlinger.
I forrige måned demonstrerte jeg hvordan jeg skulle sette sammen et grafisk brukergrensesnitt fra komponenter levert av Java-klassebibliotekets abstrakte vindusverktøy. Etter å ha samlet noen få slike grensesnitt, snakket jeg kort om temaet hendelsesbehandling, men jeg stoppet kort av en full beskrivelse av hendelsesbehandling som implementert av AWT. Denne måneden fortsetter vi der vi slapp.
Å være begivenhetsdrevet
I en fjern fortid måtte et program som ønsket å vite hva brukeren gjorde, aktivt samle inn slik informasjon selv. I praksis betydde dette at etter at et program var initialisert, gikk det inn i en stor sløyfe der det gjentatte ganger så ut for å se om brukeren gjorde noe interessant (for eksempel ved å trykke på en knapp, trykke på en tast, bevege en glidebryter, bevege musen) og deretter tok passende tiltak. Denne teknikken er kjent som avstemning.
Polling får jobben gjort, men har en tendens til å være uhåndterlig når den brukes i moderne applikasjoner av to relaterte grunner: For det første har bruken av polling en tendens til å skyve all hendelseshåndteringskode til ett sted (inne i den store sløyfen); for det andre har de resulterende interaksjonene i den store sløyfen en tendens til å være komplekse. I tillegg krever avstemning at et program skal sitte i en løkke og konsumere CPU-sykluser, mens de venter på at brukeren skal gjøre noe - et alvorlig sløsing med en verdifull ressurs.
AWT løste disse problemene ved å omfavne et annet paradigme, et som ligger til grunn for alle moderne vindussystemer: hendelsesdrevet programmering. Innenfor AWT tilhører alle brukerhandlinger et abstrakt sett med ting som kalles arrangementer. En hendelse beskriver, i tilstrekkelig detalj, en bestemt brukerhandling. I stedet for at programmet aktivt samler brukergenererte hendelser, varsler Java-kjøretiden programmet når en interessant hendelse inntreffer. Programmer som håndterer brukerinteraksjon på denne måten, sies å være det hendelsesdrevet.
Arrangementsklassen
Arrangementsklassen er den primære spilleren i arrangementsspillet. Den prøver å fange opp de grunnleggende egenskapene til alle brukergenererte hendelser. Tabell 1 lister opp de offentlige datamedlemmene levert av klassen Event.
Type | Navn | Beskrivelse |
Gjenstand | mål | En referanse til komponenten som opprinnelig mottok hendelsen. |
lang | når | Tidspunktet da hendelsen skjedde. |
int | id | Hendelsestypen (se seksjonen Hendelsestyper for mer informasjon). |
int | x | X-koordinaten som handlingen skjedde i forhold til komponenten som for tiden behandler hendelsen. For en gitt hendelse vil x-koordinaten endres i verdi når hendelsen beveger seg oppover i komponenthierarkiet. Opprinnelsen til koordinatplanet er i komponentens øvre venstre hjørne. |
int | y | Y-koordinaten som handlingen skjedde i forhold til komponenten som for tiden behandler hendelsen. For en gitt hendelse vil y-koordinaten endres i verdi når hendelsen beveger seg oppover i komponenthierarkiet. Opprinnelsen til koordinatplanet er i komponentens øvre venstre hjørne. |
int | nøkkel | For tastaturhendelser ble tastekoden til tasten bare trykket. Verdien vil vanligvis være Unicode-verdien til tegnet nøkkelen representerer. Andre muligheter inkluderer verdier for spesialtastene HJEM, SLUT, F1, F2, og så videre. |
int | modifikatorer | En aritmetisk eller ønsket kombinasjon av verdiene SHIFT_MASK, CTRL_MASK, META_MASK og ALT_MASK. Verdien representerer tilstanden til henholdsvis skift, kontroll, meta og alt. |
int | clickCount | Antall museklikk på rad. Dette data-medlemmet er bare viktig i MOUSE_DOWN-hendelser. |
Gjenstand | arg | Et hendelsesavhengig argument. For Button-objekter er dette objektet et strengobjekt som inneholder teksturetiketten til knappen. |
Som jeg vil forklare i delen med tittelen Arrangementssending og formidling, er en forekomst av klasse Hendelse vanligvis opprettet av Java run-time system. Det er imidlertid mulig for et program å lage og sende hendelser til komponenter via deres postEvent ()
metode.
Arrangementstyper
Som nevnt ovenfor er hendelsesklassen en modell av et brukergrensesnitt. Arrangementer faller naturlig inn i kategorier basert på typen hendelse (hendelsestypen indikeres av id
data-medlem). Tabell 2 viser alle hendelsene definert av AWT, sortert etter kategori.
Det kan være lærerikt å se hendelsesgenerering i aksjon. Knappen i figur 1, når den trykkes, oppretter en hendelsesleser som viser hendelsesinformasjon om hendelsene nettleseren mottar. Kildekoden for hendelsesleseren er tilgjengelig her.
Du trenger en Java-aktivert nettleser for å se denne appletenFigur 1: Hendelsesgenerering i aksjon
Arrangementssending og formidling
Tenk på appleten i figur 2. Den består av to forekomster av Button-klassen, innebygd i en forekomst av Panel-klassen. Denne forekomsten av Panel-klassen er selv innebygd i en annen forekomst av Panel-klassen. Den siste forekomsten av Panel-klassen ligger under en forekomst av klassen TextArea, og begge forekomster er innebygd i en forekomst av Applet-klassen. Figur 3 presenterer elementene som utgjør denne appleten som er lagt ut som et tre, med TextArea- og Button-forekomster som bladene, og en Applet-forekomst som roten. (For mer informasjon om den hierarkiske utformingen av komponenter i et brukergrensesnitt, les forrige måneds introduksjon til AWT.)
Du trenger en Java-aktivert nettleser for å se denne appletenFigur 2: Klasser innebygd i klasser
Figur 3: Tre av appletelementer (hierarki)
Når en bruker samhandler med appleten i figur 2, oppretter Java-kjøretidssystemet en forekomst av klasse Event og fyller sine datamedlemmer med informasjon som beskriver handlingen. Java-kjøretidssystemet lar deretter appleten håndtere hendelsen. Det begynner med komponenten som opprinnelig mottok hendelsen (for eksempel knappen som ble klikket på) og beveger seg opp komponenttreet, komponent for komponent, til den når beholderen øverst på treet. Underveis har hver komponent muligheten til å ignorere hendelsen eller reagere på den på en (eller flere) av følgende måter:
- Endre datamedlemmene til hendelsesforekomsten
- Ta grep og utfør noen beregninger basert på informasjonen i arrangementet
- Angi for Java-kjøretidssystemet at hendelsen ikke skal spre seg lenger opp i treet
Java kjøretidssystem overfører hendelsesinformasjon til en komponent via komponentens handleEvent ()
metode. Alle gyldige handleEvent ()
metoder må være av formen
public boolean handleEvent (Event e)
En hendelsesbehandler krever en enkelt informasjon: en referanse til forekomsten av hendelsesklassen som inneholder informasjon om hendelsen som nettopp skjedde.
Verdien returnert fra handleEvent ()
metoden er viktig. Det indikerer for Java kjøretidssystem om hendelsen har blitt håndtert fullstendig i hendelsesbehandleren eller ikke. En sann verdi indikerer at hendelsen er håndtert og forplantningen skal stoppe. En falsk verdi indikerer at hendelsen er ignorert, ikke kunne håndteres eller har blitt håndtert ufullstendig og bør fortsette oppover treet.
Tenk på følgende beskrivelse av en imaginær brukers interaksjon med appleten i figur 2. Brukeren klikker på knappen merket "One". Kjøretidssystemet på Java samler informasjon om hendelsen (antall klikk, plasseringen av klikket, tidspunktet klikket skjedde og komponenten som mottok klikket) og pakker den informasjonen i en forekomst av hendelsesklassen. Java-kjøretidssystemet begynner deretter på komponenten som ble klikket på (i dette tilfellet knappen merket "One"), og via en samtale til komponentens handleEvent ()
metode, gir komponenten en sjanse til å reagere på hendelsen. Hvis komponenten ikke håndterer hendelsen eller håndterer hendelsen ufullstendig (angitt med en returverdi på false), tilbyr Java-kjøretidssystemet hendelsesforekomsten til neste høyere komponent i treet - i dette tilfellet en forekomst av Panelet klasse. Java kjøretidssystem fortsetter på denne måten til hendelsen håndteres eller kjøretidssystemet går tom for komponenter for å prøve. Figur 4 illustrerer banen til denne hendelsen når appleten prøver å håndtere den.
Figur 4: Stien til en hendelse
Hver komponent som utgjør appleten i figur 2, legger til en linje i TextArea-objektet som indikerer at den mottok en hendelse. Deretter lar hendelsen forplante seg til neste komponent i treet. Oppføring 1 inneholder koden for en typisk handleEvent ()
metode. Den komplette kildekoden for denne appleten er tilgjengelig her.
public boolean handleEvent (Event evt) {if (evt.id == Event.ACTION_EVENT) {ta.appendText ("Panel" + str + "saw action ... \ n"); } annet hvis (evt.id == Event.MOUSE_DOWN) {ta.appendText ("Panel" + str + "så musen ned ... \ n"); }
returner super.handleEvent (evt); }
Oppføring 1: En typisk handleEvent ()
metode
Begivenhetshjelpermetoder
De handleEvent ()
metoden er ett sted en programmerer kan sette applikasjonskode for håndtering av hendelser. Noen ganger vil en komponent imidlertid bare være interessert i hendelser av en bestemt type (for eksempel mushendelser). I slike tilfeller kan programmereren plassere koden i en hjelpermetode, i stedet for å plassere den i handleEvent ()
metode.
Her er en liste over hjelpemetodene som er tilgjengelige for programmerere. Det er ingen hjelpemetoder for visse typer arrangementer.
handling (Event evt, Object what)
gotFocus (Event evt, Object what)
lostFocus (Event evt, Object what)
mouseEnter (hendelse evt, int x, int y)
mouseExit (hendelse evt, int x, int y)
mouseMove (hendelse evt, int x, int y)
mouseUp (hendelse evt, int x, int y)
mouseDown (hendelse evt, int x, int y)
mouseDrag (hendelse evt, int x, int y)
keyDown (hendelse evt, int-tast)
keyUp (hendelse evt, int-tast)
false for å indikere at hjelpemetoden ikke taklet hendelsen.
Gjennomføringen av handleEvent ()
metode levert av klasse Komponent påkaller hver hjelpermetode. Av denne grunn er det viktig at de omdefinerte implementeringene av handleEvent ()
metoden i avledede klasser slutter alltid med utsagnet
returner super.handleEvent (e);
Koden i Listing 2 illustrerer denne regelen.
public boolean handleEvent (Event e) {if (e.target instanceof MyButton) {// gjør noe ... return true; }
returner super.handleEvent (e); }
Oppføring 2: Regel for avslutning av uttalelse i handleEvent ()
metode
Unnlatelse av å følge denne enkle regelen vil forhindre riktig påkallelse av hjelpemetoder.
Figur 5 inneholder en applet som håndterer musehendelser utelukkende gjennom kode plassert i hjelpermetoder. Kildekoden er tilgjengelig her.
Begivenhet | evt | Neste arrangement i en lenket liste over hendelser. |
Vindushendelser | ||
Vindushendelser genereres som svar på endringer i tilstanden til et vindu, ramme eller dialog. | ||
Begivenhet | ID | |
WINDOW_DESTROY | 201 | |
WINDOW_EXPOSE | 202 | |
WINDOW_ICONIFY | 203 | |
WINDOW_DEICONIFY | 204 | |
WINDOW_MOVED | 205 | |
Tastaturhendelser | ||
Tastaturhendelser genereres som svar på tastene som trykkes og slippes mens en komponent har inngangsfokus. | ||
Begivenhet | ID | |
TASTETRYKK | 401 | |
KEY_RELEASE | 402 | |
KEY_ACTION | 403 | |
KEY_ACTION_RELEASE | 404 | |
Mushendelser | ||
Mushendelser genereres som svar på mushandlinger som skjer innenfor grensen til en komponent. | ||
Begivenhet | ID | |
MOUSE_DOWN | 501 | |
MOUSE_UP | 502 | |
MOUSE_MOVE | 503 | |
MOUSE_ENTER | 504 | |
MOUSE_EXIT | 505 | |
MUSE_DRAG | 506 | |
Bla gjennom hendelser | ||
Rullehendelser genereres som svar på manipulering av rullefelt. | ||
Begivenhet | ID | |
SCROLL_LINE_UP | 601 | |
SCROLL_LINE_DOWN | 602 | |
SCROLL_PAGE_UP | 603 | |
SCROLL_PAGE_DOWN | 604 | |
SCROLL_ABSOLUTE | 605 | |
Liste hendelser | ||
Listehendelser genereres som svar på valg som er gjort i en liste. | ||
Begivenhet | ID | |
LIST_SELECT | 701 | |
LIST_DESELECT | 702 | |
Diverse hendelser | ||
Diverse hendelser genereres som svar på en rekke handlinger. | ||
Begivenhet | ID | |
ACTION_EVENT | 1001 | |
LOAD_FILE | 1002 | |
LAGRE FILEN | 1003 | |
GOT_FOCUS | 1004 | |
LOST_FOCUS | 1005 |
Lær mer om dette emnet
- Java-veiledningen av Mary Campione og Kathy Walrath. Den elektroniske utkastversjonen er tilgjengelig på //java.sun.com/tutorial/index.html.
Denne historien, "Java and event handling", ble opprinnelig utgitt av JavaWorld.