Programmering

Java og begivenhedshåndtering

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.

TypeNavnBeskrivelse
ObjektmålEn henvisning til den komponent, der oprindeligt modtog begivenheden.
langhvornårDet tidspunkt, hvor begivenheden fandt sted.
intidHændelsestypen (se afsnittet Hændelsestyper for mere information).
intxDen 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.
intyY-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.
intnøgleVed 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.
intmodifikatorerEn 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.
intclickCountAntallet af på hinanden følgende museklik. Dette datamedlem er kun signifikant i MOUSE_DOWN begivenheder.
ObjektargEt hændelsesafhængigt argument. For knapobjekter er dette objekt et strengobjekt, der indeholder knapens tekstmærkat.
Tabel 1: Offentlige datamedlemmer leveret af klassehændelse

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.

Tabel 2: Begivenheder 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 applet

Figur 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 applet

Figur 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.

BegivenhedevtDen 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.
BegivenhedID
WINDOW_DESTROY201
WINDOW_EXPOSE202
WINDOW_ICONIFY203
WINDOW_DEICONIFY204
WINDOW_MOVED205
Tastaturbegivenheder
Tastaturhændelser genereres som reaktion på taster, der trykkes og frigives, mens en komponent har inputfokus.
BegivenhedID
TASTETRYK401
KEY_RELEASE402
KEY_ACTION403
KEY_ACTION_RELEASE404
Musbegivenheder
Mushændelser genereres som svar på mushandlinger, der forekommer inden for en komponents grænser.
BegivenhedID
MOUSE_DOWN501
MOUSE_UP502
MOUSE_MOVE503
MOUSE_ENTER504
MOUSE_EXIT505
MUSE_DRAG506
Rul begivenheder
Rullehændelser genereres som reaktion på manipulation af rullebjælker.
BegivenhedID
SCROLL_LINE_UP601
SCROLL_LINE_DOWN602
SCROLL_PAGE_UP603
SCROLL_PAGE_DOWN604
SCROLL_ABSOLUTE605
Liste begivenheder
Listehændelser genereres som svar på valg foretaget på en liste.
BegivenhedID
LIST_SELECT701
LIST_DESELECT702
Diverse begivenheder
Diverse begivenheder genereres som reaktion på en række handlinger.
BegivenhedID
ACTION_EVENT1001
LOAD_FILE1002
GEM FILEN1003
GOT_FOCUS1004
LOST_FOCUS1005
Todd Sundsted har programmeret siden computere blev tilgængelige i stationære modeller. Selvom det oprindeligt var interesseret i at oprette distribuerede objektapplikationer i C ++, flyttede Todd til Java-programmeringssproget, da Java blev et oplagt valg for den slags ting. Ud over skrivning leverer Todd internet- og webapplikationskonsulenttjenester til virksomheder i det sydøstlige USA.

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.