Java i rukovanje događajima

Većina programa, da bi bili korisni, moraju odgovarati na naredbe korisnika. Da bi to učinili, Java programi oslanjaju se na događaje koji opisuju radnje korisnika.

Prošli mjesec pokazao sam kako sastaviti grafičko korisničko sučelje od komponenata koje pruža apstraktni alat za prozore Java knjižnice klase. Nakon sastavljanja nekoliko takvih sučelja, kratko sam razgovarao o temi rukovanja događajima, ali zaustavio sam se u cjelosti s opisom rukovanja događajima koji je implementirao AWT. Ovaj mjesec nastavljamo tamo gdje smo stali.

Da bude vođen događajima

U dalekoj prošlosti program koji je želio znati što korisnik radi morao je sam aktivno prikupljati takve podatke. U praksi je to značilo da je nakon što se program inicijalizirao ušao u veliku petlju u kojoj je u više navrata gledao čini li korisnik nešto zanimljivo (na primjer, pritiskom gumba, dodirivanjem tipke, pomicanjem klizača, pomicanjem miša) a zatim poduzeo odgovarajuću akciju. Ova je tehnika poznata kao anketiranje .

Anketa završava posao, ali je tendencija biti nezgrapna kada se koristi u modernim aplikacijama iz dva povezana razloga: Prvo, upotreba ankete nastoji gurnuti sav kôd za upravljanje događajima na jedno mjesto (unutar velike petlje); drugo, rezultirajuće interakcije unutar velike petlje imaju tendenciju da budu složene. Osim toga, anketiranje zahtijeva da program sjedi u petlji, trošeći cikluse procesora, dok čeka korisnika da nešto učini - ozbiljno rasipanje dragocjenog resursa.

AWT je ove probleme riješio prihvaćajući drugačiju paradigmu, onu koja je u osnovi svih suvremenih prozorskih sustava: programiranje vođeno događajima. Unutar AWT-a, sve radnje korisnika pripadaju apstraktnom skupu stvari koje se nazivaju događaji . Događaj dovoljno detaljno opisuje određenu radnju korisnika. Umjesto da program aktivno prikuplja događaje koje generiraju korisnici, vrijeme izvođenja Java obavještava program kada se dogodi zanimljiv događaj. Za programe koji na ovaj način upravljaju interakcijom korisnika kaže se da su pokretani događajima .

Razred događaja

Razred događaja je primarni igrač u igri događaja. Pokušava uhvatiti temeljne karakteristike svih korisničkih događaja. U tablici 1. navedeni su članovi javnih podataka koje pruža razred Event.

Tip Ime Opis
Objekt cilj Referenca na komponentu koja je u početku primila događaj.
dugo kada Točka u trenutku kada se događaj dogodio.
int iskaznica Vrsta događaja (pogledajte odjeljak Vrste događaja za više informacija).
int x X koordinata na kojoj se dogodila radnja u odnosu na komponentu koja trenutno obrađuje događaj. Za dati događaj, x koordinata će se mijenjati u vrijednosti kako se događaj kreće prema hijerarhiji komponente. Izvor koordinatne ravnine nalazi se u gornjem lijevom kutu komponente.
int g Y koordinata na kojoj se dogodila radnja u odnosu na komponentu koja trenutno obrađuje događaj. Za dati događaj, y koordinata će se mijenjati u vrijednosti kako se događaj kreće prema hijerarhiji komponente. Izvor koordinatne ravnine nalazi se u gornjem lijevom kutu komponente.
int ključ Za događaje na tipkovnici, kod tipke upravo pritisnute tipke. Njegova će vrijednost obično biti Unicode vrijednost znaka koji ključ predstavlja. Ostale mogućnosti uključuju vrijednosti za posebne tipke HOME, END, F1, F2 itd.
int modifikatori Aritmetički kombinacija vrijednosti SHIFT_MASK, CTRL_MASK, META_MASK i ALT_MASK. Njegova vrijednost predstavlja stanje tipki shift, control, meta i alt.
int klikniteCount Broj uzastopnih klikova mišem. Ovaj je član podataka važan samo u događajima MOUSE_DOWN.
Objekt arg Argument ovisan o događaju. Za objekte gumba ovaj je objekt objekt String koji sadrži teksturnu oznaku gumba.
Tablica 1: Članovi javnih podataka koje pruža razred Event

Kao što ću objasniti u odjeljku pod naslovom Otprema i širenje događaja , instancu klase Događaj obično stvara Java run-time sustav. Međutim, moguće je da program stvara i šalje događaje komponentama putem njihove postEvent()metode.

Vrste događaja

Kao što je gore spomenuto, klasa Event model je događaja korisničkog sučelja. Događaji prirodno spadaju u kategorije ovisno o vrsti događaja (vrstu događaja označava idčlan podataka). U tablici 2. navedeni su svi događaji definirani AWT-om, poredani po kategorijama.

Tablica 2: Događaji definirani AWT-om, poredani po kategorijama

Može biti poučno vidjeti generiranje događaja na djelu. Kada se pritisne gumb na slici 1, stvara preglednik događaja koji prikazuje informacije o događajima koje preglednik prima. Izvorni kod za preglednik događaja dostupan je ovdje.

Za pregled ovog apleta potreban vam je preglednik s omogućenom Java

Slika 1: Generiranje događaja u akciji

Otpremanje i širenje događaja

Razmotrite aplet na slici 2. Sastoji se od dva primjerka klase Button, ugrađenih unutar instance klase Panel. Ova je instanca klase Panel sama ugrađena u drugu instancu klase Panel. Potonja instanca klase Panel nalazi se ispod instance klase TextArea i obje su instance ugrađene u instancu klase Applet. Slika 3 predstavlja elemente koji čine ovaj aplet postavljen u obliku stabla, s primjerima TextArea i Button kao listovima, a primjerak Applet-a kao korijenom. (Za više informacija o hijerarhijskom rasporedu komponenata u korisničkom sučelju pročitajte prošlomjesečni uvod u AWT.)

Za pregled ovog apleta potreban vam je preglednik s omogućenom Java

Slika 2: Razredi ugrađeni u razrede

Slika 3: Stablo elemenata apleta (hijerarhija)

Kada korisnik stupi u interakciju s apletom na slici 2, Java run-time sustav stvara instancu klase Event i ispunjava svoje članove podataka informacijama koje opisuju radnju. Java-run-time sustav tada omogućuje apletu da obrađuje događaj. Počinje komponentom koja je u početku primila događaj (na primjer, gumb na koji je kliknuto) i pomiče se prema stablu komponenata, komponenta po komponenta, sve dok ne dosegne spremnik na vrhu stabla. Usput, svaka komponenta ima priliku ignorirati događaj ili na njega reagirati na jedan (ili više) od sljedećih načina:

  • Izmijenite članove podataka instance događaja
  • Poduzmite akciju i izvršite izračunavanje na temelju informacija sadržanih u događaju
  • Označite Java-ovom sustavu da se događaj ne smije širiti dalje prema stablu

Java-run-time sustav prosljeđuje informacije o događaju komponenti putem metode komponente handleEvent(). Sve valjane handleEvent()metode moraju biti oblika

javni logički handleEvent (događaj e) 

Obrađivač događaja zahtijeva jedan podatak: referencu na instancu klase Event koja sadrži informacije o događaju koji se upravo dogodio.

Vrijednost vraćena iz handleEvent()metode je važna. Sustavu Java-run-time pokazuje je li događaj u potpunosti obrađen unutar obrađivača događaja. Prava vrijednost znači da je događaj obrađen i da se širenje treba zaustaviti. Lažna vrijednost znači da je događaj zanemaren, da se nije mogao obraditi ili je obrađen nepotpuno te da treba nastaviti prema stablu.

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 programira otkad su računala postala dostupna u stolnim modelima. Iako je izvorno bio zainteresiran za izgradnju distribuiranih objektnih aplikacija na C ++, Todd je prešao na programski jezik Java kad je Java postala očit izbor za takve stvari. Uz pisanje, Todd pruža usluge savjetovanja za internetske i web aplikacije tvrtkama na jugoistoku SAD-a.

Saznajte više o ovoj temi

  • Vodič za Java Mary Campione i Kathy Walrath. Verzija mrežnog nacrta dostupna je na //java.sun.com/tutorial/index.html.

Ovu je priču "Java i upravljanje događajima" izvorno objavio JavaWorld.