I když JDK 1.1 určitě zavedením modelu události delegování zjednodušila zpracování událostí, vývojářům to usnadňuje vytváření vlastních typů událostí. Zde popsaný základní postup je ve skutečnosti poměrně přímočarý. Kvůli jednoduchosti nebudu pojednávat o pojmech umožňování událostí a maskách událostí. Navíc byste měli vědět, že události vytvořené pomocí tohoto postupu nebudou zaúčtovány do fronty událostí a budou fungovat pouze s registrovanými posluchači.
V současné době se jádro Java skládá z 12 typů událostí definovaných v události java.awt
:
- ActionEvent
- Událost úpravy
- ComponentEvent
- ContainerEvent
- FocusEvent
- InputEvent
- ItemEvent
- KeyEvent
- MouseEvent
- PaintEvent
- TextEvent
- WindowEvent
Protože vytváření nových typů událostí je netriviální úkol, měli byste prozkoumat události, které jsou součástí základní Javy. Pokud je to možné, zkuste tyto typy použít místo vytváření nových.
Nastanou však chvíle, kdy bude nutné pro novou komponentu vyvinout nový typ události. Pro účely této diskuse použiji příklad jednoduché komponenty, panelu průvodce, jako prostředek k předvedení, jak vytvořit nový typ události.
Průvodce panel implementuje jednoduchý kouzelník rozhraní. Součást se skládá z panelu karty, který lze rozšířit pomocí tlačítka DALŠÍ. Tlačítko ZPĚT umožňuje přepnout na předchozí panel. K dispozici jsou také tlačítka FINISH a CANCEL.
Aby byla součást flexibilní, chtěl jsem vývojáři, který ji používá, poskytnout plnou kontrolu nad akcemi provedenými všemi tlačítky. Například když stisknete tlačítko DALŠÍ, mělo by být možné, aby vývojář nejprve zkontroloval, zda byla zadána požadovaná data na aktuálně viditelné komponentě, než přejde na další komponentu.
Při vytváření vlastního typu události existuje pět hlavních úkolů:
Vytvořte posluchače událostí
Vytvořte adaptér posluchače
Vytvořte třídu události
Upravte komponentu
- Správa více posluchačů
Postupně prozkoumáme každý z těchto úkolů a poté je všechny spojíme.
Vytvořte posluchače událostí
Jedním ze způsobů (a je jich mnoho) informování objektů, že došlo k určité akci, je vytvoření nového typu události, který by mohl být doručen registrovaným posluchačům. V případě panelu průvodce by měl posluchač podporovat čtyři různé případy událostí, jeden pro každé tlačítko.
Začnu vytvořením rozhraní posluchače. Pro každé tlačítko definuji metodu posluchače následujícím způsobem:
import java.util.EventListener; veřejné rozhraní WizardListener rozšiřuje EventListener {public abstract void nextSelected (WizardEvent e); public abstract void backSelected (WizardEvent e); public abstract void cancelSelected (WizardEvent e); public abstract void finishSelected (WizardEvent e); }
Každá metoda má jeden argument: WizardEvent
, který je definován dále. Rozhraní se rozšiřuje EventListener
, slouží k identifikaci tohoto rozhraní jako posluchače AWT.
Vytvořte adaptér posluchače
Vytvoření adaptéru pro posluchače je volitelný krok. V AWT je adaptér posluchače třída, která poskytuje výchozí implementaci pro všechny metody určitého typu posluchače. Všechny třídy adaptérů v událost java.awt
balíček poskytuje prázdné metody, které nic nedělají. Zde je třída adaptéru pro WizardListener
:
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) {}}
Při psaní třídy, která má být posluchačem průvodce, je možné rozšířit WizardAdapter
a zajistit implementaci (nebo přepsat) pouze ty metody posluchače, které jsou zajímavé. Jedná se přísně o třídu pohodlí.
Vytvořte třídu události
Dalším krokem je vytvoření skutečného událost
třída zde: 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; public static final int CANCEL_SELECTED = WIZARD_FIRST + 2; public static final int FINISH_SELECTED = WIZARD_FIRST + 3; public static final int WIZARD_LAST = WIZARD_FIRST + 3; public WizardEvent (zdroj průvodce, int id) {super (zdroj, id); }}
Dvě konstanty, WIZARD_FIRST
a WIZARD_LAST
, označte inkluzivní rozsah masek používaných touto třídou událostí. Všimněte si, že ID událostí používají RESERVED_ID_MAX
konstanta třídy AWTEvent
k určení rozsahu ID, která nebudou v rozporu s hodnotami ID události definovanými AWT. Jak jsou přidávány další komponenty AWT, RESERVED_ID_MAX
se v budoucnu může zvýšit.
Zbývající čtyři konstanty představují čtyři ID událostí, z nichž každé odpovídá jinému typu akce, jak je definováno funkcí průvodce.
ID události a zdroj události jsou dva argumenty pro konstruktor události průvodce. Zdroj události musí být typu kouzelník
- to je typ komponenty, pro kterou je událost definována. Důvodem je, že zdrojem událostí průvodce může být pouze panel průvodce. Všimněte si, že WizardEvent
třída se prodlužuje AWTEvent
.
Upravte komponentu
Dalším krokem je vybavení naší komponenty metodami, které jí umožňují registrovat a odebírat posluchače nové události.
Chcete-li doručit událost posluchači, obvykle byste zavolali příslušnou metodu posluchače událostí (v závislosti na masce události). Mohu zaregistrovat posluchače akcí, který bude přijímat akce z tlačítka NEXT a předávat je registrovaným WizardListener
předměty. The akce Provedeno
metodu posluchače akcí pro tlačítko DALŠÍ (nebo jiné akce) lze implementovat takto:
public void actionPerformed (ActionEvent e) {// nedělat nic, pokud nejsou zaregistrováni žádní posluchači, pokud se (wizardListener == null) vrátí; WizardEvent w; Zdroj průvodce = this; if (e.getSource () == nextButton) {w = nový WizardEvent (zdroj, WizardEvent.NEXT_SELECTED); wizardListener.nextSelected (w); } // zpracovat zbytek tlačítek průvodce podobným způsobem}
Poznámka: Ve výše uvedeném příkladu jekouzelník
samotný panel je posluchačem souboru DALŠÍ knoflík.
Po stisknutí tlačítka NEXT se objeví nové WizardEvent
je vytvořen s příslušným zdrojem a maskou, která odpovídá stisknutému tlačítku NEXT.
V příkladu řádek
wizardListener.nextSelected (w);
Odkazuje na průvodce čarodějů
objekt, který je soukromou členskou proměnnou pro kouzelník
a je typu WizardListener
. Tento typ jsme definovali jako první krok při vytváření nové události komponenty.
Na první pohled se zdá, že výše uvedený kód omezuje počet posluchačů na jednoho. Soukromá proměnná průvodce čarodějů
není pole a pouze jedno dalšíVybráno
je proveden hovor. Abychom vysvětlili, proč výše uvedený kód ve skutečnosti nepředstavuje toto omezení, prozkoumejme, jak jsou přidáni posluchači.
Každá nová součást, která generuje události (předdefinované nebo nové), musí poskytovat dvě metody: jednu pro podporu přidání posluchače a jednu pro podporu odstranění posluchače. V případě kouzelník
třídy, tyto metody jsou:
public synchronized void addWizardListener (WizardListener l) {wizardListener = WizardEventMulticaster.add (wizardListener, l); } public synchronized void removeWizardListener (WizardListener l) {wizardListener = WizardEventMulticaster.remove (wizardListener, l); }
Obě metody volají členy statické metody třídy WizardEventMulticaster
.
Správa více posluchačů
I když je možné použít a Vektor
pro správu více posluchačů definuje JDK 1.1 speciální třídu pro udržování seznamu posluchačů: AWTEventMulticaster
. Jedna instance vícesměrového vysílání udržuje odkazy na dva objekty posluchače. Protože multicaster je také samotným posluchačem (implementuje všechna rozhraní posluchače), každý ze dvou posluchačů, které sleduje, může být také multicaster, což vytváří řetězec posluchačů událostí nebo multicasterů:
Pokud je posluchač také multicaster, pak představuje odkaz v řetězci. Jinak je pouze posluchačem a je tedy posledním prvkem v řetězci.
Bohužel není možné jednoduše znovu použít AWTEventMulticaster
zpracovat vícesměrové vysílání událostí pro nové typy událostí. Nejlepší, co lze udělat, je rozšířit AWT multicaster, i když tato operace je docela sporná. AWTEventMulticaster
obsahuje 56 metod. Z toho 51 metod poskytuje podporu pro 12 typů událostí a jejich odpovídající posluchače, které jsou součástí AWT. Pokud podtřídu AWTEventMulticaster
, stejně je nikdy nepoužijete. Ze zbývajících pěti metod addInternal (EventListener, EventListener)
, a remove (EventListener)
je třeba překódovat. (Říkám překódováno, protože v AWTEventMulticaster
, addInternal
je statická metoda, a proto ji nelze přetížit. Z dosud neznámých důvodů odstranit
volá addInternal
a je třeba jej přetížit.)
Dvě metody, Uložit
a saveInternal
, poskytují podporu pro streamování objektů a lze je znovu použít v nové třídě multicaster. Poslední metoda, která podporuje rutiny odebrání posluchače, removeInternal
, lze také znovu použít za předpokladu, že nové verze odstranit
a addInternal
byly implementovány.
Kvůli jednoduchosti se chystám podtřídu AWTEventMulticaster
, ale s velmi malým úsilím je možné kódovat odstranit
, Uložit
, a saveInternal
a mít plně funkční, samostatný multicaster událostí.
Zde je multicaster událostí implementovaný ke zpracování WizardEvent
:
importovat java.awt.AWTEventMulticaster; import java.util.EventListener; veřejná třída WizardEventMulticaster rozšiřuje AWTEventMulticaster implementuje WizardListener {chráněný WizardEventMulticaster (EventListener a, EventListener b) {super (a, b); } public static WizardListener add (WizardListener a, WizardListener b) {return (WizardListener) addInternal (a, b); } public static WizardListener remove (WizardListener l, WizardListener oldl) {return (WizardListener) removeInternal (l, oldl); } public void nextSelected (WizardEvent e) {// casting exception will never occurs in this case // casting _is_ needed because this multicaster may // handle more than just one listener 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áněný statický EventListener addInternal (EventListener a, EventListener b) {if (a == null) return b; if (b == null) vrátit a; vrátit nový WizardEventMulticaster (a, b); } chráněný EventListener remove (EventListener oldl) {if (oldl == a) return b; if (oldl == b) vrátit a; EventListener a2 = removeInternal (a, oldl); EventListener b2 = removeInternal (b, oldl); if (a2 == a && b2 == b) vrátit toto; návrat addInternal (a2, b2); }}
Metody ve třídě multicaster: Recenze
Podívejme se na metody, které jsou součástí třídy multicaster výše. Konstruktor je chráněn a aby získal nový WizardEventMulticaster
, statický přidat (WizardListener, WizardListener)
metoda musí být volána. Trvá dva posluchače jako argumenty, které představují dva kusy řetězce posluchače, které mají být propojeny:
Chcete-li spustit nový řetězec, použijte null jako první argument.
Chcete-li přidat nového posluchače, použijte existující posluchač jako první argument a nový posluchač jako druhý argument.
To je ve skutečnosti to, co bylo provedeno v kódu třídy kouzelník
které jsme již prozkoumali.
Další statická rutina je remove (WizardListener, WizardListener)
. První argument je posluchač (nebo multicaster posluchače) a druhý je posluchač, který má být odstraněn.
Byly přidány čtyři veřejné, nestatické metody pro podporu šíření událostí prostřednictvím řetězce událostí. Pro každého WizardEvent
případ (tj. vybraný další, zpět, zrušit a dokončit) existuje jedna metoda. Tyto metody musí být implementovány, protože WizardEventMulticaster
nářadí WizardListener
, což vyžaduje přítomnost čtyř metod.
Jak to všechno funguje společně
Pojďme nyní prozkoumat, jak multicaster ve skutečnosti používá kouzelník
. Předpokládejme, že je vytvořen objekt průvodce a jsou přidáni tři posluchači, čímž se vytvoří řetězec posluchačů.
Zpočátku soukromá proměnná průvodce čarodějů
třídy kouzelník
je null. Když se tedy volá WizardEventMulticaster.add (WizardListener, WizardListener)
první argument, průvodce čarodějů
, je null a druhý není (nemá smysl přidávat nulový posluchač). The přidat
metoda zase volá addInternal
. Protože jeden z argumentů je null, návrat z addInternal
je nenulový posluchač. Návrat se šíří do přidat
metoda, která vrací posluchače, který nemá hodnotu null addWizardListener
metoda. Tady průvodce čarodějů
proměnná je nastavena na přidávaného nového posluchače.