Programmering

Java Tips 35: Opprett nye hendelsestyper i Java

Mens JDK 1.1 absolutt har strømlinjeformet hendelsesbehandling med introduksjonen av delegasjonshendelsesmodellen, gjør det ikke det enkelt for utviklere å lage sine egne hendelsestyper. Den grunnleggende prosedyren som er beskrevet her er faktisk ganske grei. For enkelhets skyld vil jeg ikke diskutere begreper aktivering av hendelser og hendelsesmasker. I tillegg bør du vite at hendelser opprettet ved hjelp av denne prosedyren ikke vil bli lagt ut i hendelseskøen og vil bare fungere med registrerte lyttere.

For tiden består Java-kjernen av 12 hendelsestyper definert i java.awt. hendelser:

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

Fordi det å opprette nye hendelsestyper er en ikke-triviell oppgave, bør du undersøke hendelser som er en del av kjernen i Java. Hvis mulig, prøv å bruke disse typene i stedet for å lage nye.

Det vil imidlertid være tider når en ny hendelsestype må utvikles for en ny komponent. I forbindelse med denne diskusjonen vil jeg bruke eksemplet på en enkel komponent, et veiviserpanel, som et middel for å demonstrere hvordan du lager en ny hendelsestype.

Et veiviserpanel implementerer et enkelt veiviseren grensesnitt. Komponenten består av et kortpanel som kan avanseres ved hjelp av NEXT-knappen. BACK-knappen lar deg bla til forrige panel. FINISH- og CANCEL-knappene er også tilgjengelig.

For å gjøre komponenten fleksibel, ønsket jeg å gi full kontroll over handlingene som ble tatt av alle knappene til utvikleren som bruker den. Når du for eksempel trykker på NESTE-knappen, bør det være mulig for utvikleren å først sjekke om nødvendige data ble skrevet inn på komponenten som er synlig før de går videre til neste komponent.

Det er fem hovedoppgaver for å lage din egen arrangementstype:

  • Lag en lytter til hendelser

  • Lag en lytteradapter

  • Opprett en arrangementsklasse

  • Endre komponenten

  • Administrere flere lyttere

Vi vil undersøke hver av disse oppgavene etter tur og deretter sette dem alle sammen.

Lag en lytter til hendelser

En måte (og det er mange) å informere objekter om at en bestemt handling har skjedd, er å lage en ny hendelsestype som kan leveres til registrerte lyttere. Når det gjelder veiviserpanelet, bør en lytter støtte fire forskjellige hendelsessaker, en for hver knapp.

Jeg begynner med å lage et lyttergrensesnitt. For hver knapp definerer jeg en lyttermetode på følgende måte:

importere java.util.EventListener; offentlig grensesnitt WizardListener utvider EventListener {public abstract void nextSelected (WizardEvent e); offentlig abstrakt ugyldig backSelected (WizardEvent e); offentlig abstrakt ugyldig annullertSelected (WizardEvent e); offentlig abstrakt ugyldig finishSelected (WizardEvent e); } 

Hver metode tar ett argument: WizardEvent, som defineres neste. Merk at grensesnittet utvides EventListener, brukes til å identifisere dette grensesnittet som en AWT-lytter.

Lag en lytteradapter

Å lage et lytteradapter er et valgfritt trinn. I AWT er en lytteradapter en klasse som gir en standardimplementering for alle metoder av en bestemt lyttertype. Alle adapterklasser i java.awt.event pakken gir tomme metoder som ikke gjør noe. Her er en adapterklasse for 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 som skal være en trolllytter, er det mulig å utvide WizardAdapter og gi implementering for (eller overstyre) bare de lyttermetodene som er av interesse. Dette er strengt tatt en praktisk klasse.

Opprett en arrangementsklasse

Det neste trinnet er å lage det faktiske Begivenhet klasse her: WizardEvent.

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

To konstanter, WIZARD_FIRST og WIZARD_LAST, merk det inkluderende utvalget av masker som brukes av denne hendelsesklassen. Merk at hendelses-ID-ene bruker RESERVED_ID_MAX konstant i klassen AWTEvent for å bestemme rekkevidden av ID-er som ikke kommer i konflikt med hendelses-ID-verdiene definert av AWT. Etter hvert som flere AWT-komponenter legges til, blir RESERVED_ID_MAX kan øke i fremtiden.

De resterende fire konstanter representerer fire hendelses-ID-er, som hver tilsvarer en annen handlingstype, som definert av veiviserens funksjonalitet.

Hendelses-ID og hendelseskilde er to argumenter for veiviserens hendelseskonstruktør. Hendelseskilde må være av typen Veiviser - det er komponenttypen hendelsen er definert for. Begrunnelsen er at bare et veiviserpanel kan være en kilde til veiviserhendelser. Merk at WizardEvent klasse utvider AWTEvent.

Endre komponenten

Det neste trinnet er å utstyre komponenten vår med metoder som gjør det mulig å registrere og fjerne lyttere til det nye arrangementet.

For å levere en hendelse til en lytter, vil man normalt kalle den riktige hendelseslyttermetoden (avhengig av hendelsesmasken). Jeg kan registrere en handlingslytter for å motta handlingshendelser fra NEXT-knappen og videreformidle dem til registrerte WizardListener gjenstander. De handling utført metoden til handlingslytteren for NESTE (eller andre handlinger) -knappen kan implementeres som følger:

public void actionPerformed (ActionEvent e) {// gjør ingenting hvis ingen lyttere er registrert hvis (wizardListener == null) returnerer; WizardEvent w; Veiviserkilde = dette; hvis (e.getSource () == nextButton) {w = ny WizardEvent (kilde, WizardEvent.NEXT_SELECTED); wizardListener.nextSelected (w); } // håndter resten av veiviserknappene på en lignende måte} 

Merk: I eksemplet ovenfor erVeiviserselve panelet er lytteren for NESTE knapp.

Når du trykker på NESTE-knappen, en ny WizardEvent blir opprettet med riktig kilde og maske som tilsvarer at NESTE-knappen trykkes.

I eksemplet, linjen

 wizardListener.nextSelected (w); 

refererer til wizardListener objekt som er en privat medlemsvariabel for Veiviser og er av typen WizardListener. Vi har definert denne typen som det første trinnet i å lage en ny komponenthendelse.

Ved første øyekast ser koden ovenfor ut til å begrense antall lyttere til en. Den private variabelen wizardListener er ikke en matrise, og bare en neste Valgt samtalen blir ringt. For å forklare hvorfor koden ovenfor ikke utgjør den begrensningen, la oss undersøke hvordan lyttere blir lagt til.

Hver nye komponent som genererer hendelser (forhåndsdefinert eller ny), må gi to metoder: en for å støtte lyttertilsetning og en for å støtte lytterfjerning. I tilfelle av Veiviser klasse, er disse metodene:

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

Begge metodene ringer til medlemmer av statiske metoder i klassen WizardEventMulticaster.

Administrere flere lyttere

Selv om det er mulig å bruke en Vector for å administrere flere lyttere definerer JDK 1.1 en spesiell klasse for å opprettholde en lytterliste: AWTEventMulticaster. En enkelt multicaster-forekomst opprettholder referanser til to lytterobjekter. Fordi multicaster også er en lytter (den implementerer alle lyttergrensesnitt), kan hver av de to lytterne den holder oversikt over også være multicaster, og dermed skape en kjede av eventlyttere eller multicaster:

Hvis en lytter også er en multicaster, representerer den et ledd i kjeden. Ellers er det bare en lytter og er dermed det siste elementet i kjeden.

Dessverre er det ikke mulig bare å gjenbruke AWTEventMulticaster for å håndtere multicasting for hendelser for nye typer arrangementer. Det beste som kan gjøres er å utvide AWT multicaster, selv om denne operasjonen er ganske tvilsom. AWTEventMulticaster inneholder 56 metoder. Av disse gir 51 metoder støtte for de 12 hendelsestypene og tilhørende lyttere som er en del av AWT. Hvis du underklasser AWTEventMulticaster, du vil aldri bruke dem uansett. Av de resterende fem metodene, addInternal (EventListener, EventListener), og fjern (EventListener) må kodes på nytt. (Jeg sier kodet fordi i AWTEventMulticaster, addInternal er en statisk metode og kan derfor ikke overbelastes. Av grunner som jeg ikke kjenner på nåværende tidspunkt, fjerne ringer til addInternal og det må overbelastes.)

To metoder, lagre og lagre internt, gir støtte for objektstrømming og kan brukes på nytt i den nye multicaster-klassen. Den siste metoden som støtter rutiner for å fjerne lyttere, removeInternal, kan også gjenbrukes, forutsatt at nye versjoner av fjerne og addInternal har blitt implementert.

For enkelhets skyld skal jeg underklasse AWTEventMulticaster, men med veldig liten innsats er det mulig å kode fjerne, lagre, og lagre internt og har et fullt funksjonelt, frittstående arrangement multicaster.

Her er arrangement multicaster som implementert for å håndtere WizardEvent:

importere java.awt.AWTEventMulticaster; importere java.util.EventListener; offentlig klasse WizardEventMulticaster utvider AWTEventMulticaster implementerer WizardListener {beskyttet WizardEventMulticaster (EventListener a, EventListener b) {super (a, b); } offentlig statisk WizardListener add (WizardListener a, WizardListener b) {return (WizardListener) addInternal (a, b); } offentlig statisk WizardListener fjern (WizardListener l, WizardListener oldl) {retur (WizardListener) removeInternal (l, oldl); } public void nextSelected (WizardEvent e) {// casting-unntak vil aldri forekomme i dette tilfellet // casting _is_ needed fordi denne multicaster kan // håndtere mer enn bare en lytter hvis (a! = null) ((WizardListener) a). nesteVelgt (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). avbryt valgt (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; return addInternal (a2, b2); }} 

Metoder i multicaster-klassen: En gjennomgang

La oss se gjennom metodene som inngår i multicaster-klassen ovenfor. Konstruktøren er beskyttet, og for å skaffe en ny WizardEventMulticaster, en statisk legg til (WizardListener, WizardListener) metoden må kalles. Det tar to lyttere som argumenter som representerer to deler av en lytterkjede som skal knyttes sammen:

  • For å starte en ny kjede, bruk null som det første argumentet.

  • For å legge til en ny lytter, bruk den eksisterende lytteren som det første argumentet og en ny lytter som det andre argumentet.

Dette er faktisk det som er gjort i koden for klassen Veiviser som vi allerede har undersøkt.

En annen statisk rutine er fjern (WizardListener, WizardListener). Det første argumentet er en lytter (eller lytter-multicaster), og den andre er en lytter som skal fjernes.

Fire offentlige, ikke-statiske metoder ble lagt til for å støtte forplantning av hendelser gjennom arrangementskjeden. For hver WizardEvent tilfelle (det vil si neste, tilbake, avbryt og fullfør valgt) er det en metode. Disse metodene må implementeres siden WizardEventMulticaster redskaper WizardListener, som igjen krever at de fire metodene er til stede.

Hvordan det hele fungerer sammen

La oss nå undersøke hvordan multicaster faktisk brukes av Veiviser. La oss anta at et veiviserobjekt er konstruert og tre lyttere blir lagt til, og skaper en lytterkjede.

Opprinnelig den private variabelen wizardListener av klassen Veiviser er null. Så når en ringes til WizardEventMulticaster.add (WizardListener, WizardListener), det første argumentet, wizardListener, er null og den andre ikke (det gir ikke mening å legge til en null-lytter). De legge til metoden, i sin tur, samtaler addInternal. Siden et av argumentene er null, er retur av addInternal er lytteren som ikke er null. Avkastningen forplanter seg til legge til metode som returnerer den som ikke er null, til addWizardListener metode. Der er det wizardListener variabelen er satt til den nye lytteren som legges til.

$config[zx-auto] not found$config[zx-overlay] not found