Programmering

Java Tip 35: Opret nye begivenhedstyper i Java

Mens JDK 1.1 helt sikkert har strømlinet håndtering af begivenheder med introduktionen af ​​delegationsbegivenhedsmodellen, gør det det ikke let for udviklere at oprette deres egne begivenhedstyper. Den grundlæggende procedure, der er beskrevet her, er faktisk ret ligetil. Af hensyn til enkelheden vil jeg ikke diskutere begreber om aktivering af begivenheder og begivenhedsmasker. Derudover skal du vide, at begivenheder oprettet ved hjælp af denne procedure ikke vil blive sendt til begivenhedskøen og kun vil fungere med registrerede lyttere.

I øjeblikket består Java-kernen af ​​12 begivenhedstyper defineret i java.awt. begivenheder:

  • ActionEvent
  • JusteringEvent
  • ComponentEvent
  • ContainerEvent
  • FocusEvent
  • InputEvent
  • ItemEvent
  • KeyEvent
  • MouseEvent
  • PaintEvent
  • TextEvent
  • WindowEvent

Da oprettelse af nye begivenhedstyper er en ikke-triviel opgave, bør du undersøge begivenheder, der er en del af kernen i Java. Hvis det er muligt, så prøv at bruge disse typer i stedet for at oprette nye.

Der vil dog være tidspunkter, hvor en ny begivenhedstype skal udvikles til en ny komponent. I forbindelse med denne diskussion vil jeg bruge eksemplet på en simpel komponent, et guide-panel, som et middel til at demonstrere, hvordan man opretter en ny begivenhedstype.

Et guide-panel implementerer et simpelt guiden interface. Komponenten består af et kortpanel, der kan avanceres ved hjælp af NEXT-knappen. BACK-knappen giver dig mulighed for at vende til det forrige panel. FINISH- og CANCEL-knapperne findes også.

For at gøre komponenten fleksibel, ønskede jeg at give fuld kontrol over de handlinger, der blev udført af alle knapperne, til udvikleren, der bruger den. For eksempel, når der trykkes på NEXT-knappen, skal det være muligt for udvikleren først at kontrollere, om de krævede data blev indtastet på den komponent, der aktuelt er synlig, før de går videre til næste komponent.

Der er fem hovedopgaver i oprettelsen af ​​din egen begivenhedstype:

  • Opret en begivenhedslytter

  • Opret en lytteradapter

  • Opret en begivenhedsklasse

  • Rediger komponenten

  • Håndtering af flere lyttere

Vi undersøger hver af disse opgaver igen og sætter dem alle sammen.

Opret en begivenhedslytter

En måde (og der er mange) at informere objekter om, at en bestemt handling er sket, er at oprette en ny begivenhedstype, der kan leveres til registrerede lyttere. Når det gælder guiden, skal en lytter understøtte fire forskellige hændelsessager, en for hver knap.

Jeg starter med at oprette en lyttergrænseflade. For hver knap definerer jeg en lyttermetode på følgende måde:

importere java.util.EventListener; offentlig grænseflade WizardListener udvider EventListener {offentlig abstrakt ugyldig nextSelected (WizardEvent e); offentlig abstrakt ugyldig backSelected (WizardEvent e); offentlig abstrakt ugyldig annullering Valgt (WizardEvent e); offentlig abstrakt ugyldig finishSelected (WizardEvent e); } 

Hver metode tager et argument: WizardEvent, som defineres derefter. Bemærk, at grænsefladen udvides EventListener, bruges til at identificere denne grænseflade som en AWT-lytter.

Opret en lytteradapter

Oprettelse af en lytteradapter er et valgfrit trin. I AWT er en lytteradapter en klasse, der giver en standardimplementering for alle metoder af en bestemt lyttertype. Alle adapterklasser i java.awt.event pakken giver tomme metoder, der ikke gør noget. Her er en adapterklasse til WizardListener:

offentlig klasse WizardAdapter implementerer WizardListener {public void nextSelected (WizardEvent e) {} public void backSelected (WizardEvent e) {} public void cancelSelected (WizardEvent e) {} public void finishSelected (WizardEvent e) {}} 

Når du skriver en klasse, der skal være en guiden lytter, er det muligt at udvide WizardAdapter og kun give implementering til (eller tilsidesætte) de lyttermetoder, der er af interesse. Dette er strengt taget en bekvemmelighedsklasse.

Opret en begivenhedsklasse

Det næste trin er at oprette den aktuelle Begivenhed klasse her: WizardEvent.

importer java.awt.AWTEvent; offentlig klasse WizardEvent udvider AWTEvent {public static final int WIZARD_FIRST = AWTEvent.RESERVED_ID_MAX + 1; offentlig statisk endelig int NEXT_SELECTED = WIZARD_FIRST; offentlig statisk endelig int BACK_SELECTED = WIZARD_FIRST + 1; offentlig statisk endelig int CANCEL_SELECTED = WIZARD_FIRST + 2; offentlig statisk endelig int FINISH_SELECTED = WIZARD_FIRST + 3; offentlig statisk endelig int WIZARD_LAST = WIZARD_FIRST + 3; public WizardEvent (Wizard source, int id) {super (source, id); }} 

To konstanter, WIZARD_FIRST og WIZARD_LAST, marker det inkluderende udvalg af masker, der bruges af denne begivenhedsklasse. Bemærk, at begivenheds-id'erne bruger RESERVED_ID_MAX konstant i klassen AWTEvent for at bestemme rækkevidden af ​​id'er, der ikke er i konflikt med begivenheds-id-værdierne defineret af AWT. Efterhånden som der tilføjes flere AWT-komponenter, bliver RESERVED_ID_MAX kan stige i fremtiden.

De resterende fire konstanter repræsenterer fire hændelses-id'er, der hver svarer til en anden handlingstype, som defineret af guidenes funktionalitet.

Hændelses-id og hændelseskilde er to argumenter for guiden hændelseskonstruktør. Begivenhedskilde skal være af typen guiden - det er den komponenttype, begivenheden er defineret til. Begrundelsen er, at kun et wizard-panel kan være en kilde til wizard-begivenheder. Bemærk, at WizardEvent klasse udvides AWTEvent.

Rediger komponenten

Det næste trin er at udstyre vores komponent med metoder, der gør det muligt at registrere og fjerne lyttere til den nye begivenhed.

For at aflevere en begivenhed til en lytter, kalder man normalt den passende begivenhedslyttermetode (afhængigt af begivenhedsmasken). Jeg kan registrere en handlingslytter for at modtage handlingsbegivenheder fra NEXT-knappen og videresende dem til registreret WizardListener genstande. Det handling udført Handlingslytterens metode til knappen NÆSTE (eller andre handlinger) kunne implementeres som følger:

public void actionPerformed (ActionEvent e) {// gør ingenting, hvis der ikke er nogen lyttere registreret, hvis (wizardListener == null) vender tilbage; WizardEvent w; Wizard kilde = dette; hvis (e.getSource () == nextButton) {w = ny WizardEvent (kilde, WizardEvent.NEXT_SELECTED); wizardListener.nextSelected (w); } // håndter resten af ​​guiden knapperne på en lignende måde} 

Bemærk: I ovenstående eksempel erguidenselve panelet er lytteren til NÆSTE knap.

Når der trykkes på NEXT-knappen, en ny WizardEvent oprettes med den relevante kilde og maske, der svarer til, at der trykkes på NEXT-knappen.

I eksemplet er linjen

 wizardListener.nextSelected (w); 

henviser til wizardListener objekt, der er en privat medlemsvariabel for guiden og er af typen WizardListener. Vi har defineret denne type som det første trin i oprettelse af en ny komponentbegivenhed.

Ved første øjekast synes koden ovenfor at begrænse antallet af lyttere til en. Den private variabel wizardListener er ikke en matrix, og kun en næsteValgte opkald foretages. For at forklare, hvorfor koden ovenfor faktisk ikke udgør den begrænsning, lad os undersøge, hvordan lyttere tilføjes.

Hver ny komponent, der genererer begivenheder (foruddefineret eller ny), skal give to metoder: en til at understøtte tilføjelse af lytter og en til at fjerne fjernelse af lytter. I tilfælde af guiden klasse, disse metoder er:

 offentlig synkroniseret ugyldig addWizardListener (WizardListener l) {wizardListener = WizardEventMulticaster.add (wizardListener, l); } offentlig synkroniseret ugyldighed removeWizardListener (WizardListener l) {wizardListener = WizardEventMulticaster.remove (wizardListener, l); } 

Begge metoder ringer til medlemmer af statiske metoder i klassen WizardEventMulticaster.

Håndtering af flere lyttere

Mens det er muligt at bruge en Vektor for at administrere flere lyttere definerer JDK 1.1 en særlig klasse til opretholdelse af en listerliste: AWTEventMulticaster. En enkelt multicaster-instans opretholder referencer til to lytterobjekter. Fordi multicaster også er en lytter (den implementerer alle lyttergrænseflader), kan hver af de to lyttere, som den holder styr på, også være multicaster og derved skabe en kæde af lyttere eller multicaster:

Hvis en lytter også er en multicaster, repræsenterer den et led i kæden. Ellers er det kun en lytter og er dermed det sidste element i kæden.

Desværre er det ikke muligt blot at genbruge AWTEventMulticaster til at håndtere begivenhed multicasting til nye begivenhedstyper. Det bedste, der kan gøres, er at udvide AWT-multicaster, selvom denne operation er ret tvivlsom. AWTEventMulticaster indeholder 56 metoder. Af disse giver 51 metoder support til de 12 begivenhedstyper og deres tilsvarende lyttere, der er en del af AWT. Hvis du underklasse AWTEventMulticaster, du vil aldrig bruge dem alligevel. Ud af de resterende fem metoder, addInternal (EventListener, EventListener)og fjern (EventListener) skal kodes igen. (Jeg siger kodet fordi i AWTEventMulticaster, addInternal er en statisk metode og kan derfor ikke overbelastes. Af grunde, der ikke er kendt for mig på dette tidspunkt, fjerne ringer til addInternal og det skal overbelastes.)

To metoder, Gemme og gemIntern, yde support til objektstreaming og kan genbruges i den nye multicaster-klasse. Den sidste metode, der understøtter rutiner til fjernelse af lytter, Fjern internt, kan også genbruges, forudsat at nye versioner af fjerne og addInternal er blevet implementeret.

For enkelheds skyld vil jeg underklasse AWTEventMulticaster, men med meget lidt indsats er det muligt at kode fjerne, Gemmeog gemIntern og har et fuldt funktionelt, enkeltstående event multicaster.

Her er event multicaster som implementeret til at håndtere WizardEvent:

importer java.awt.AWTEventMulticaster; importere java.util.EventListener; offentlig klasse WizardEventMulticaster udvider AWTEventMulticaster implementerer WizardListener {beskyttet WizardEventMulticaster (EventListener a, EventListener b) {super (a, b); } offentlig statisk WizardListener tilføj (WizardListener a, WizardListener b) {return (WizardListener) addInternal (a, b); } offentlig statisk WizardListener fjern (WizardListener l, WizardListener oldl) {return (WizardListener) removeInternal (l, oldl); } public void nextSelected (WizardEvent e) {// casting exception vil aldrig forekomme i dette tilfælde // casting _is_ needed, fordi denne multicaster muligvis // håndterer mere end kun en lytter, hvis (a! = null) ((WizardListener) a). næsteValgte (e); hvis (b! = null) ((WizardListener) b) .nextSelected (e); } public void backSelected (WizardEvent e) {if (a! = null) ((WizardListener) a) .backSelected (e); hvis (b! = null) ((WizardListener) b) .backSelected (e); } public void cancelSelected (WizardEvent e) {if (a! = null) ((WizardListener) a) .cancelSelected (e); hvis (b! = null) ((WizardListener) b) .cancelSelected (e); } public void finishSelected (WizardEvent e) {if (a! = null) ((WizardListener) a) .finishSelected (e); hvis (b! = null) ((WizardListener) b). finishSelected (e); } beskyttet statisk EventListener addInternal (EventListener a, EventListener b) {if (a == null) return b; hvis (b == null) returnerer a; returner ny WizardEventMulticaster (a, b); } beskyttet EventListener fjern (EventListener oldl) {hvis (oldl == a) returner b; hvis (oldl == b) returnerer a; EventListener a2 = removeInternal (a, oldl); EventListener b2 = removeInternal (b, oldl); hvis (a2 == a && b2 == b) returnerer dette; returnere addInternal (a2, b2); }} 

Metoder i multicaster-klassen: En gennemgang

Lad os gennemgå de metoder, der er en del af multicaster-klassen ovenfor. Konstruktøren er beskyttet og for at få en ny WizardEventMulticaster, en statisk tilføj (WizardListener, WizardListener) metode skal kaldes. Det tager to lyttere som argumenter, der repræsenterer to stykker af en lyttekæde, der skal forbindes:

  • For at starte en ny kæde skal du bruge null som det første argument.

  • For at tilføje en ny lytter skal du bruge den eksisterende lytter som det første argument og en ny lytter som det andet argument.

Dette er faktisk det, der er gjort i koden til klassen guiden som vi allerede har undersøgt.

En anden statisk rutine er fjern (WizardListener, WizardListener). Det første argument er en lytter (eller lytter-multicaster), og det andet er en lytter, der skal fjernes.

Fire offentlige, ikke-statiske metoder blev tilføjet til støtte for udbredelse af begivenheder gennem begivenhedskæden. For hver WizardEvent tilfældet (dvs. næste, tilbage, annullering og afslutning valgt) er der en metode. Disse metoder skal implementeres, da WizardEventMulticaster redskaber WizardListener, hvilket igen kræver, at de fire metoder er til stede.

Hvordan det hele fungerer sammen

Lad os nu undersøge, hvordan multicaster faktisk bruges af guiden. Lad os antage, at der oprettes et guiderobjekt, og tre lyttere tilføjes, hvilket skaber en lyttekæde.

Oprindeligt den private variabel wizardListener af klassen guiden er nul. Så når der foretages et opkald til WizardEventMulticaster.add (WizardListener, WizardListener), det første argument, wizardListener, er null og det andet ikke (det giver ikke mening at tilføje en null-lytter). Det tilføje metode til gengæld opkald addInternal. Da et af argumenterne er nul, returneres addInternal er lytteren, der ikke er nul. Returen udbreder sig til tilføje metode, der returnerer den ikke-nul lytteren til addWizardListener metode. Der er wizardListener variabel er indstillet til den nye lytter, der tilføjes.