Programovanie

Java Tip 35: Vytvorte nové typy udalostí v prostredí Java

Aj keď JDK 1.1 určite má zavedenie modelu udalosti delegovania zjednodušené spracovanie udalostí, vývojárom to uľahčuje vytváranie ich vlastných typov udalostí. Tu popísaný základný postup je v skutočnosti dosť priamy. Kvôli jednoduchosti nebudem rozoberať koncepty umožňovania udalostí a masiek udalostí. Okrem toho by ste mali vedieť, že udalosti vytvorené pomocou tohto postupu nebudú zaradené do poradia udalostí a budú fungovať iba s registrovanými poslucháčmi.

V súčasnosti jadro Java pozostáva z 12 typov udalostí definovaných v java.awt.udalosti:

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

Pretože vytváranie nových typov udalostí nie je triviálna úloha, mali by ste preskúmať udalosti, ktoré sú súčasťou základnej Javy. Pokiaľ je to možné, skúste radšej použiť tieto typy ako vytvárať nové.

Občas však bude potrebné vyvinúť nový typ udalosti pre nový komponent. Na účely tejto diskusie použijem príklad jednoduchej súčasti, sprievodcovský panel, ako prostriedok na demonštráciu spôsobu vytvorenia nového typu udalosti.

Sprievodca panel implementuje jednoduché čarodejník rozhranie. Komponent sa skladá z panelu karty, ktorý je možné rozšíriť pomocou tlačidla NEXT. Tlačidlo SPÄŤ umožňuje otočenie na predchádzajúci panel. K dispozícii sú tiež tlačidlá FINISH a CANCEL.

Aby bola súčasť flexibilná, chcel som vývojárovi, ktorý ju používa, poskytnúť úplnú kontrolu nad akciami vykonanými všetkými tlačidlami. Napríklad keď stlačíte tlačidlo ĎALŠIE, mal by mať vývojár možnosť najskôr skontrolovať, či boli zadané požadované údaje o práve viditeľnom komponente, a až potom prejsť na ďalší komponent.

Existuje päť hlavných úloh pri vytváraní vlastného typu udalosti:

  • Vytvorte si poslucháča udalostí

  • Vytvorte adaptér poslucháča

  • Vytvorte triedu udalosti

  • Upravte komponent

  • Správa viacerých poslucháčov

Každú z týchto úloh postupne preskúmame a potom ich spojíme dokopy.

Vytvorte si poslucháča udalostí

Jedným zo spôsobov (a je ich veľa) informovania objektov o tom, že došlo k určitej akcii, je vytvorenie nového typu udalosti, ktorý by sa mohol doručiť registrovaným poslucháčom. V prípade panela sprievodcu by mal poslucháč podporovať štyri rôzne prípady udalostí, jeden pre každé tlačidlo.

Začínam vytvorením rozhrania poslucháča. Pre každé tlačidlo definujem metódu poslucháča nasledujúcim spôsobom:

import java.util.EventListener; verejné rozhranie WizardListener rozširuje EventListener {verejné abstraktné neplatné nextSelected (WizardEvent e); public abstract void backSelected (WizardEvent e); public abstract void cancelSelected (WizardEvent e); public abstract void finishSelected (WizardEvent e); } 

Každá metóda má jeden argument: WizardEvent, ktorý je definovaný ďalej. Upozorňujeme, že rozhranie sa rozširuje EventListener, ktorý sa používa na identifikáciu tohto rozhrania ako poslucháča AWT.

Vytvorte adaptér poslucháča

Vytvorenie adaptéra poslucháča je voliteľný krok. V AWT je adaptér poslucháča trieda, ktorá poskytuje predvolenú implementáciu pre všetky metódy určitého typu poslucháča. Všetky triedy adaptérov v java.awt.event balík poskytuje prázdne metódy, ktoré nič nerobia. Tu je trieda adaptéra pre Sprievodca sprievodcom:

public class WizardAdapter implementuje WizardListener {public void nextSelected (WizardEvent e) {} public void backSelected (WizardEvent e) {} public void cancelSelected (WizardEvent e) {} public void finishSelected (WizardEvent e) {}} 

Pri písaní triedy, ktorá má byť čarodejníkom, je možné rozšíriť WizardAdapter a poskytnúť implementáciu (alebo prepísať) iba tých metód poslucháča, ktoré sú zaujímavé. Toto je prísne trieda pohodlia.

Vytvorte triedu udalosti

Ďalším krokom je vytvorenie skutočného Udalosť trieda tu: WizardEvent.

import java.awt.AWTEvent; public class WizardEvent extends AWTEvent {public static final int WIZARD_FIRST = AWTEvent.RESERVED_ID_MAX + 1; public static final int NEXT_SELECTED = WIZARD_FIRST; public static final int BACK_SELECTED = WIZARD_FIRST + 1; verejný statický konečný int CANCEL_SELECTED = WIZARD_FIRST + 2; verejný statický konečný int FINISH_SELECTED = WIZARD_FIRST + 3; public static final int WIZARD_LAST = WIZARD_FIRST + 3; public WizardEvent (zdroj sprievodcu, int id) {super (zdroj, id); }} 

Dve konštanty, WIZARD_FIRST a WIZARD_LAST, označte inkluzívny rozsah masiek používaných touto triedou udalosti. Upozorňujeme, že identifikátory udalostí používajú RESERVED_ID_MAX konštanta triedy AWTEvent na určenie rozsahu ID, ktoré nebudú v rozpore s hodnotami ID udalosti definovanými v AWT. Po pridaní ďalších komponentov AWT sa RESERVED_ID_MAX sa môže v budúcnosti zvýšiť.

Zvyšné štyri konštanty predstavujú štyri identifikátory udalostí, z ktorých každý zodpovedá inému typu akcie, ako je definované funkčnosťou sprievodcu.

ID udalosti a zdroj udalosti sú dva argumenty pre konštruktor udalostí sprievodcu. Zdroj udalosti musí byť typu Čarodejník - to je typ komponentu, pre ktorý je udalosť definovaná. Dôvod je ten, že zdrojom sprievodných udalostí môže byť iba panel sprievodcu. Všimnite si, že WizardEvent trieda predlžuje AWTEvent.

Upravte komponent

Ďalším krokom je vybavenie našej súčasti metódami, ktoré jej umožňujú registrovať a odstraňovať poslucháčov novej udalosti.

Na doručenie udalosti poslucháčovi by sa zvyčajne dalo zavolať príslušnú metódu poslucháča udalostí (v závislosti od masky udalosti). Môžem zaregistrovať poslucháča akcií, aby prijímal udalosti akcií z tlačidla NEXT a odosielať ich registrovaným Sprievodca sprievodcom predmety. The actionPerformed Metóda poslucháča akcií pre tlačidlo ĎALŠIE (alebo iné akcie) by mohla byť implementovaná takto:

public void actionPerformed (ActionEvent e) {// neurobiť nič, ak nie sú zaregistrovaní žiadni poslucháči, ak sa (wizardListener == null) vráti; WizardEvent w; Zdroj sprievodcu = toto; if (e.getSource () == nextButton) {w = nový WizardEvent (zdroj, WizardEvent.NEXT_SELECTED); wizardListener.nextSelected (w); } // zaobchádza so zvyškom tlačidiel sprievodcu podobným spôsobom} 

Poznámka: Vo vyššie uvedenom príkladeČarodejníksamotný panel je poslucháčom súboru ĎALŠIE tlačidlo.

Po stlačení tlačidla NEXT sa zobrazí nové WizardEvent je vytvorený s príslušným zdrojom a maskou, ktorá zodpovedá stlačenému tlačidlu NEXT.

V príklade riadok

 wizardListener.nextSelected (w); 

odkazuje na sprievodca sprievodcom objekt, ktorý je súkromnou členskou premennou pre Čarodejník a je typu Sprievodca sprievodcom. Tento typ sme definovali ako prvý krok pri vytváraní udalosti novej súčasti.

Na prvý pohľad sa zdá, že vyššie uvedený kód obmedzuje počet poslucháčov na jedného. Súkromná premenná sprievodca sprievodcom nie je pole a iba jedno ďalšieVybrané uskutoční sa hovor. Aby sme vysvetlili, prečo vyššie uvedený kód vlastne nepredstavuje toto obmedzenie, preskúmajme, ako sú pridaní poslucháči.

Každá nová súčasť, ktorá generuje udalosti (preddefinované alebo nové), musí obsahovať dve metódy: jednu na podporu pridania poslucháča a jednu na podporu odstránenia poslucháča. V prípade Čarodejník triedy, sú to tieto metódy:

 verejné synchronizované void addWizardListener (WizardListener l) {wizardListener = WizardEventMulticaster.add (wizardListener, l); } verejné synchronizované void removeWizardListener (WizardListener l) {wizardListener = WizardEventMulticaster.remove (wizardListener, l); } 

Obe metódy volajú členov statickej metódy triedy WizardEventMulticaster.

Správa viacerých poslucháčov

Aj keď je možné použiť a Vektor na správu viacerých poslucháčov definuje JDK 1.1 špeciálnu triedu na udržiavanie zoznamu poslucháčov: AWTEventMulticaster. Jedna inštancia viacnásobného vysielania udržuje odkazy na dva objekty poslucháča. Pretože multicaster je aj samotným poslucháčom (implementuje všetky rozhrania poslucháča), každý z dvoch poslucháčov, ktoré sleduje, môže byť tiež multicaster, čím vytvára reťazec poslucháčov udalostí alebo multicaster:

Ak je poslucháč aj vysielací program, potom predstavuje odkaz v reťazci. V opačnom prípade je iba poslucháčom a je teda posledným prvkom v reťazci.

Bohužiaľ nie je možné jednoducho znovu použiť AWTEventMulticaster na spracovanie hromadného vysielania udalostí pre nové typy udalostí. Najlepšie je možné rozšíriť AWT multicaster, aj keď táto operácia je dosť otázna. AWTEventMulticaster obsahuje 56 metód. Z toho 51 metód poskytuje podporu pre 12 typov udalostí a ich zodpovedajúcich poslucháčov, ktorí sú súčasťou AWT. Ak podtriedu AWTEventMulticaster, aj tak ich nikdy nepoužiješ. Zo zvyšných piatich metód addInternal (EventListener, EventListener)a remove (EventListener) treba prekódovať. (Hovorím prekódované, pretože v AWTEventMulticaster, addInternal je statická metóda, a preto ju nemožno preťažiť. Z dôvodov, ktoré mi v tejto chvíli nie sú známe, odstrániť zavolá na číslo addInternal a treba to preťažiť.)

Dve metódy, uložiť a saveInternal, poskytujú podporu pre streamovanie objektov a je možné ich znova použiť v novej triede multicaster. Posledná metóda, ktorá podporuje rutiny odstraňovania poslucháčov, removeInternal, možno tiež znovu použiť za predpokladu, že nové verzie odstrániť a addInternal boli implementované.

Pre jednoduchosť idem do podtriedy AWTEventMulticaster, ale s veľmi malým úsilím je možné kódovať odstrániť, uložiťa saveInternal a mať plne funkčný, samostatný multicaster udalostí.

Tu je multicaster udalosti implementovaný do spracovania WizardEvent:

import java.awt.AWTEventMulticaster; import java.util.EventListener; verejná trieda WizardEventMulticaster rozširuje AWTEventMulticaster implementuje WizardListener {chránený WizardEventMulticaster (EventListener a, EventListener b) {super (a, b); } public static WizardListener add (WizardListener a, WizardListener b) {return (WizardListener) addInternal (a, b); } verejný statický WizardListener remove (WizardListener l, WizardListener oldl) {return (WizardListener) removeInternal (l, oldl); } public void nextSelected (WizardEvent e) {// casting výnimka sa v tomto prípade nikdy nevyskytne // casting _is_ je potrebný, pretože tento multicaster môže // zvládnuť viac ako len jedného poslucháča if (a! = null) ((WizardListener) a). nextSelected (e); if (b! = null) ((WizardListener) b) .nextSelected (e); } public void backSelected (WizardEvent e) {if (a! = null) ((WizardListener) a) .backSelected (e); if (b! = null) ((WizardListener) b) .backSelected (e); } public void cancelSelected (WizardEvent e) {if (a! = null) ((WizardListener) a) .cancelSelected (e); if (b! = null) ((WizardListener) b) .cancelSelected (e); } public void finishSelected (WizardEvent e) {if (a! = null) ((WizardListener) a) .finishSelected (e); if (b! = null) ((WizardListener) b) .finishSelected (e); } chránený statický EventListener addInternal (EventListener a, EventListener b) {if (a == null) return b; if (b == null) vráti a; vrátiť nový WizardEventMulticaster (a, b); } chránený EventListener remove (EventListener oldl) {if (oldl == a) return b; if (oldl == b) vráti a; EventListener a2 = removeInternal (a, oldl); EventListener b2 = removeInternal (b, oldl); if (a2 == a && b2 == b) vrátiť toto; návrat addInternal (a2, b2); }} 

Metódy v triede multicaster: Recenzia

Pozrime sa na metódy, ktoré sú súčasťou triedy multicaster vyššie. Konštruktér je chránený, a aby získal nové WizardEventMulticaster, statický pridať (WizardListener, WizardListener) treba volať metódu. Trvá dvoch poslucháčov ako argumenty, ktoré predstavujú dva časti reťazca poslucháčov, ktoré majú byť prepojené:

  • Ak chcete založiť nový reťazec, ako prvý argument použite null.

  • Ak chcete pridať nového poslucháča, použite existujúci poslucháč ako prvý argument a nový poslucháč ako druhý argument.

Toto sa v skutočnosti urobilo v kóde pre triedu Čarodejník ktoré sme už preskúmali.

Ďalšou statickou rutinou je odstrániť (WizardListener, WizardListener). Prvý argument je poslucháč (alebo multicaster poslucháča) a druhý je poslucháč, ktorý sa má odstrániť.

Na podporu šírenia udalostí v reťazci udalostí boli pridané štyri verejné, nestatické metódy. Pre každý WizardEvent prípad (tj. nasledujúci, späť, zrušiť a dokončiť vybraný) existuje jedna metóda. Tieto metódy musia byť implementované, pretože WizardEventMulticaster náradie Sprievodca sprievodcom, čo si vyžaduje prítomnosť týchto štyroch metód.

Ako to všetko spolu funguje

Poďme sa teraz pozrieť na to, ako je multicaster v skutočnosti používaný Čarodejník. Predpokladajme, že je zostavený objekt sprievodcu a sú pridaní traja poslucháči, čím sa vytvorí reťazec poslucháčov.

Spočiatku súkromná premenná sprievodca sprievodcom triedy Čarodejník je neplatné. Keď sa teda uskutoční hovor na číslo WizardEventMulticaster.add (WizardListener, WizardListener)prvý argument, sprievodca sprievodcom, je null a druhé nie (nemá zmysel pridávať nulového poslucháča). The pridať metóda zasa hovory addInternal. Pretože jeden z argumentov je nulový, návrat z addInternal je nenulový poslucháč. Návrat sa šíri do pridať metóda, ktorá vráti nenulový poslucháč do addWizardListener metóda. Tam sprievodca sprievodcom premenná je nastavená na nového pridávaného poslucháča.

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