Programavimas

„Java“ patarimas 35: sukurkite naujus „Java“ įvykių tipus

Nors JDK 1.1, be abejo, supaprastino įvykių tvarkymą, įvedus delegavimo renginių modelį, kūrėjams nėra lengva kurti savo įvykių tipus. Čia aprašyta pagrindinė procedūra iš tikrųjų yra gana paprasta. Siekdamas paprastumo, neaptarinėsiu įvykių įgalinimo ir įvykių kaukių sąvokų. Be to, turėtumėte žinoti, kad įvykiai, sukurti naudojant šią procedūrą, nebus paskelbti įvykių eilėje ir veiks tik su registruotais klausytojais.

Šiuo metu „Java“ pagrindą sudaro 12 įvykių tipų, apibrėžtų java.awt.events:

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

Kadangi naujų įvykių tipų kūrimas nėra nereikšminga užduotis, turėtumėte išnagrinėti įvykius, kurie yra „Java“ pagrindinė dalis. Jei įmanoma, pabandykite naudoti tuos tipus, o ne kurti naujus.

Tačiau bus atvejų, kai naujam komponentui reikės sukurti naują įvykio tipą. Šios diskusijos tikslais naudosiu paprasto komponento, vedlio skydelio, pavyzdį, kaip priemonę parodyti, kaip sukurti naują įvykio tipą.

Vedlio skydelis įgyvendina paprastą burtininkas sąsaja. Komponentą sudaro kortelių skydelis, kurį galima išplėsti naudojant mygtuką NEXT. BACK mygtukas leidžia pereiti prie ankstesnio skydelio. Taip pat pateikiami mygtukai FINISH ir CANCEL.

Kad komponentas būtų lankstus, norėjau suteikti visišką visų mygtukų veiksmų kontrolę kūrėjui, kuris jį naudoja. Pavyzdžiui, paspaudus mygtuką NEXT, kūrėjui turėtų būti suteikta galimybė pirmiausia patikrinti, ar reikalingi duomenys buvo įvesti į šiuo metu matomą komponentą prieš pereinant prie kito komponento.

Kuriant savo įvykio tipą yra penkios pagrindinės užduotys:

  • Sukurkite įvykių klausytoją

  • Sukurkite klausytojo adapterį

  • Sukurkite įvykių klasę

  • Pakeiskite komponentą

  • Kelių klausytojų valdymas

Mes išnagrinėsime kiekvieną iš šių užduočių paeiliui ir tada sujungsime jas visas.

Sukurkite įvykių klausytoją

Vienas iš būdų (ir yra daug) objektų informavimo, kad įvyko tam tikras veiksmas, yra naujo įvykio tipo sukūrimas, kuris galėtų būti pristatytas registruotiems klausytojams. Vedlio skydelio atveju klausytojas turėtų palaikyti keturis skirtingus įvykių atvejus, po vieną kiekvienam mygtukui.

Pirmiausia sukuriu klausytojo sąsają. Kiekvienam mygtukui aš nusakau klausytojo metodą taip:

importuoti java.util.EventListener; viešoji sąsaja „WizardListener“ pratęsia „EventListener“ {public abstract void nextSelected (WizardEvent e); public abstract void backSelected („WizardEvent e“); viešas abstraktus negaliojantis cancelSelected („WizardEvent e“); public abstract void finishSelected („WizardEvent e“); } 

Kiekvienam metodui reikalingas vienas argumentas: „WizardEvent“, kuris yra apibrėžtas toliau. Atkreipkite dėmesį, kad sąsaja tęsiasi „EventListener“, naudojamas identifikuoti šią sąsają kaip AWT klausytoją.

Sukurkite klausytojo adapterį

Klausytojo adapterio sukūrimas yra neprivalomas žingsnis. AWT klausytojo adapteris yra klasė, teikianti numatytąjį visų tam tikro tipo klausytojų metodų įgyvendinimą. Visos adapterių klasės java.awt.event pakete pateikiami tušti metodai, kurie nieko nedaro. Čia yra adapterių klasė, skirta „WizardListener“:

public class „WizardAdapter“ įgyvendina „WizardListener“ {public void nextSelected (WizardEvent e) {} public void backSelected (WizardEvent e) {} public void cancelSelected (WizardEvent e) {} public void finishSelected (WizardEvent e) {}} 

Rašant klasę, kuri turi būti vedlio klausytoja, galima pratęsti „WizardAdapter“ ir pateikti (arba nepaisyti) tik tuos dominančius klausytojo metodus. Tai griežtai patogumo klasė.

Sukurkite įvykių klasę

Kitas žingsnis - sukurti faktinį Įvykis klasė čia: „WizardEvent“.

importuoti java.awt.AWTEvent; viešosios klasės „WizardEvent“ pratęsia 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; viešasis statinis finalas FINISH_SELECTED = WIZARD_FIRST + 3; viešasis statinis finalas WIZARD_LAST = WIZARD_FIRST + 3; public WizardEvent (Wizard source, int id) {super (source, id); }} 

Dvi konstantos, WIZARD_FIRST ir WIZARD_LAST, pažymėkite šios renginių klasės naudojamų kaukių asortimentą. Atminkite, kad įvykių ID naudoja RESERVED_ID_MAX klasės konstanta AWTEvent nustatyti ID diapazoną, kuris neprieštaraus AWT apibrėžtoms įvykio ID reikšmėms. Pridedant daugiau AWT komponentų, RESERVED_ID_MAX ateityje gali padidėti.

Likusios keturios konstantos reiškia keturis įvykių ID, kurių kiekvienas atitinka skirtingą veiksmo tipą, kaip apibrėžta vedlio funkcijose.

Įvykio ID ir įvykio šaltinis yra du vedlio įvykių konstruktoriaus argumentai. Įvykio šaltinis turi būti tipo burtininkas - tai komponento tipas, kuriam yra apibrėžtas įvykis. Priežastis yra ta, kad tik vedlio skydelis gali būti vedlio įvykių šaltinis. Atkreipkite dėmesį, kad „WizardEvent“ klasė tęsiasi AWTEvent.

Pakeiskite komponentą

Kitas žingsnis - aprūpinti mūsų komponentą metodais, leidžiančiais užregistruoti ir pašalinti klausytojus naujam įvykiui.

Norint pristatyti įvykį klausytojui, paprastai reikia iškviesti atitinkamą įvykių klausytojo metodą (priklausomai nuo įvykio kaukės). Aš galiu užregistruoti veiksmo klausytoją, kad gautumėte veiksmo įvykius iš mygtuko NEXT, ir persiųstu juos registruotiems „WizardListener“ objektai. actionPerformed NEXT (ar kitų veiksmų) mygtuko veiksmų klausytojo metodas gali būti įgyvendintas taip:

public void actionPerformed (ActionEvent e) {// nieko nedaryti, jei nė vienas klausytojas nėra registruotas, jei (wizardListener == null) grįžta; „WizardEvent w“; Vedlio šaltinis = tai; if (e.getSource () == nextButton) {w = naujas „WizardEvent“ (šaltinis, „WizardEvent.NEXT_SELECTED“); wizardListener.nextSelected (w); } // panašiai tvarkykite likusius vedlio mygtukus} 

Pastaba: Aukščiau pateiktame pavyzdyjeburtininkaspati panelė yra klausytoja KITAS mygtuką.

Paspaudus mygtuką NEXT, naujas „WizardEvent“ yra sukurtas su atitinkamu šaltiniu ir kauke, atitinkančiu paspaudžiamą mygtuką NEXT.

Pavyzdyje linija

 wizardListener.nextSelected (w); 

reiškia vedlysListener objektas, kuris yra privatus nario kintamasis burtininkas ir yra tipo „WizardListener“. Mes apibrėžėme šį tipą kaip pirmą žingsnį kuriant naują komponentinį įvykį.

Iš pirmo žvilgsnio atrodo, kad aukščiau pateiktas kodas apriboja klausytojų skaičių iki vieno. Privatus kintamasis vedlysListener nėra masyvas, ir tik vienas kitasPasirinktas skambinama. Norėdami paaiškinti, kodėl aukščiau pateiktas kodas iš tikrųjų netaiko tokio apribojimo, panagrinėkime, kaip pridedami klausytojai.

Kiekvienam naujam komponentui, generuojančiam įvykius (iš anksto apibrėžtiems ar naujiems), reikia pateikti du metodus: vieną klausytojų papildymui palaikyti ir kitą klausytojų pašalinimą. Dėl burtininkas klasėje, šie metodai yra:

 viešai sinchronizuotas negaliojantis addWizardListener (WizardListener l) {wizardListener = WizardEventMulticaster.add (wizardListener, l); } public synchronized void removeWizardListener (WizardListener l) {wizardListener = WizardEventMulticaster.remove (wizardListener, l); } 

Abu metodai paskambina į statinio metodo klasės narius „WizardEventMulticaster“.

Kelių klausytojų valdymas

Nors galima naudoti a Vektorius Norėdami valdyti kelis klausytojus, JDK 1.1 apibrėžia specialią klasę, skirtą klausytojų sąrašui tvarkyti: AWTEventMulticaster. Viename daugiaadresiniame egzemplioriuje pateikiamos nuorodos į du klausytojo objektus. Kadangi daugialypis radijas taip pat yra klausytojas (jis įgyvendina visas klausytojo sąsajas), kiekvienas iš klausytojų, kuriuos jis stebi, taip pat gali būti daugialypiai, taip sukuriant įvykių klausytojų arba daugiaadresių grandinę:

Jei klausytojas taip pat yra multicasteris, tai reiškia grandinės grandį. Priešingu atveju tai yra tik klausytojas ir todėl yra paskutinis grandinės elementas.

Deja, neįmanoma tiesiog pakartotinai naudoti AWTEventMulticaster tvarkyti įvykių grupinį siuntimą naujiems įvykių tipams. Geriausia, ką galima padaryti, tai išplėsti AWT multicaster, nors ši operacija yra gana abejotina. AWTEventMulticaster yra 56 metodai. Iš jų 51 metodas teikia paramą 12 įvykių tipų ir juos atitinkantiems klausytojams, kurie yra AWT dalis. Jei subklasei AWTEventMulticaster, vis tiek niekada jų nenaudosite. Iš likusių penkių metodų „addInternal“ („EventListener“, „EventListener“)ir pašalinti („EventListener“) reikia perkoduoti. (Sakau, perkoduota, nes AWTEventMulticaster, addInternal yra statinis metodas, todėl jo negalima perkrauti. Dėl man dar nežinomų priežasčių pašalinti skambina addInternal ir jį reikia perkrauti.)

Du metodai, sutaupyti ir saveInternal, teikia paramą objektų srautui perduoti ir gali būti pakartotinai panaudojami naujojoje daugiaadresių klasėje. Paskutinis metodas, palaikantis klausytojus, pašalina įprastą tvarką, pašalintiVidinis, taip pat gali būti pakartotinai naudojamas, jei naujos versijos pašalinti ir addInternal buvo įgyvendinti.

Dėl paprastumo einu į poklasį AWTEventMulticaster, bet labai nedaug pastangų įmanoma koduoti pašalinti, sutaupytiir saveInternal ir turi visiškai funkcionalų, atskirą įvykių daugialypį ryšį.

Čia yra įvykių daugialypis ryšys, pritaikytas tvarkyti „WizardEvent“:

importuoti java.awt.AWTEventMulticaster; importuoti java.util.EventListener; public class WizardEventMulticaster pratęsia AWTEventMulticaster įgyvendina WizardListener {apsaugotas 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) {// perdavimo išimtis šiuo atveju niekada neįvyks. kitasPasirinktas (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); } apsaugotas statinis EventListener addInternal (EventListener a, EventListener b) {if (a == null) return b; if (b == null) grąžinti a; grąžinti naują „WizardEventMulticaster“ (a, b); } apsaugotas „EventListener“ pašalinti („EventListener oldl“) {if (oldl == a) grąžinti b; if (oldl == b) grąžinti a; EventListener a2 = removeInternal (a, oldl); EventListener b2 = removeInternal (b, oldl); if (a2 == a && b2 == b) grąžink tai; grįžti addInternal (a2, b2); }} 

Daugialypės terpės klasės metodai: apžvalga

Peržiūrėkime metodus, kurie yra aukščiau pateiktos daugialypės terpės klasės dalis. Konstruktorius yra apsaugotas ir norint gauti naują „WizardEventMulticaster“, statinis pridėti („WizardListener“, „WizardListener“) metodas turi būti vadinamas. Reikia susieti du klausytojus kaip argumentus, kurie atstovauja dviem klausytojų grandinės dalims:

  • Norėdami pradėti naują grandinę, naudokite null kaip pirmąjį argumentą.

  • Norėdami pridėti naują klausytoją, naudokite esamą klausytoją kaip pirmąjį argumentą ir naują klausytoją kaip antrąjį argumentą.

Iš tikrųjų tai buvo padaryta klasės kode burtininkas kad mes jau ištyrėme.

Kita statiška rutina yra pašalinti („WizardListener“, „WizardListener“). Pirmasis argumentas yra klausytojas (arba klausytojo daugiaadresis), o antrasis - klausytojas, kurį reikia pašalinti.

Pridedami keturi viešieji, ne statiniai metodai, kurie palaiko įvykių sklaidą per įvykių grandinę. Kiekvienam „WizardEvent“ atveju (tai yra kitas, atgal, atšaukti ir baigti pasirinktą) yra vienas metodas. Šie metodai turi būti taikomi nuo „WizardEventMulticaster“ padargai „WizardListener“, o tai savo ruožtu reikalauja keturių metodų.

Kaip visa tai veikia kartu

Panagrinėkime, kaip iš tikrųjų multicaster naudoja burtininkas. Tarkime, kad sukonstruotas vedlio objektas ir pridėti trys klausytojai, sukuriantys klausytojų grandinę.

Iš pradžių privatus kintamasis vedlysListener klasės burtininkas yra niekinis. Taigi, kai skambinama „WizardEventMulticaster.add“ („WizardListener“, „WizardListener“), pirmasis argumentas, vedlysListener, yra niekinis, o antrasis nėra (nėra prasmės pridėti nulinį klausytoją). papildyti metodas, savo ruožtu, skambina addInternal. Kadangi vienas iš argumentų yra niekinis, grąžinimas addInternal yra niekinis klausytojas. Grįžimas plinta į papildyti metodas, kuris grąžina nenulinį klausytoją į addWizardListener metodas. Ten vedlysListener kintamasis nustatomas, kad naujas klausytojas būtų pridėtas.