Swing ima veliko uporabnih razredov, ki olajšajo razvoj grafičnega uporabniškega vmesnika (GUI). Nekateri od teh razredov pa niso dobro izvedeni. En primer takega razreda je ButtonGroup
. Ta članek pojasnjuje, zakaj ButtonGroup
je slabo oblikovan in ponuja nadomestni razred, JButtonGroup
, ki podeduje od ButtonGroup
in odpravi nekatere težave.
Opomba: Izvorno kodo tega članka lahko prenesete iz virov.
ButtonGroup holes
Tu je pogost scenarij pri razvoju grafičnega uporabniškega vmesnika Swing: Izdelate obrazec za zbiranje podatkov o elementih, ki jih bo nekdo vnesel v bazo podatkov ali shranil v datoteko. Obrazec lahko vsebuje polja z besedilom, potrditvena polja, izbirne gumbe in druge pripomočke. Uporabljate ButtonGroup
razred, da združite vse izbirne gumbe, ki potrebujejo eno izbiro. Ko je oblikovanje obrazca pripravljeno, začnete izvajati podatke obrazca. Naletite na nabor izbirnih gumbov in vedeti morate, kateri gumb v skupini je bil izbran, da lahko ustrezne podatke shranite v bazo podatkov ali datoteko. Zdaj ste zaljubljeni. Zakaj? The ButtonGroup
razred vam ne daje sklica na gumb, ki je trenutno izbran v skupini.
ButtonGroup
ima getSelection ()
metoda, ki vrne model izbranega gumba (kot ButtonModel
tipa), ne samega gumba. Zdaj je to morda v redu, če lahko referenco na gumb dobite iz njegovega modela, vendar ne morete. The ButtonModel
vmesnik in njegovi izvedbeni razredi ne omogočajo pridobivanja sklica gumba iz njegovega modela. Torej s čim se ukvarjate? Poglej ButtonGroup
dokumentacijo in si oglejte getActionCommand ()
metoda. Spomnite se, da če ustvarite primer JRadioButton
z Vrvica
za besedilo, prikazano ob gumbu, in nato pokličete getActionCommand ()
na gumbu se vrne besedilo v konstruktorju. Morda si mislite, da lahko še vedno nadaljujete s kodo, ker četudi nimate sklica na gumb, imate vsaj njegovo besedilo in še vedno poznate izbrani gumb.
No, presenečenje! Vaša koda se med izvajanjem zlomi z NullPointerException
. Zakaj? Ker getActionCommand ()
v ButtonModel
vrne nič
. Če stavite (kot sem jaz) to getActionCommand ()
daje enak rezultat, ne glede na to, ali je poklican na gumbu ali na modelu (kar velja za veliko druge metode, kot so isSelected ()
, isEnabled ()
, ali getMnemonic ()
), izgubil si. Če izrecno ne pokličete setActionCommand ()
na gumbu v njegovem modelu ne nastavite ukaza action in metoda getter se vrne nič
za model. Vendar metoda pridobivanja naredi vrne besedilo gumba, ko ga pokličete. Tukaj je getActionCommand ()
metoda v PovzetekButton
, ki so ga podedovali vsi razredi gumbov v Swingu:
javni String getActionCommand () {Niz ac = getModel (). getActionCommand (); if (ac == null) {ac = getText (); } vrnitev ac; }
Ta nedoslednost pri nastavljanju in pridobivanju ukaza za dejanje je nesprejemljiva. Tej situaciji se lahko izognete, če setText ()
v PovzetekButton
nastavi ukaz dejanja modela na besedilo gumba, ko je ukaz dejanja ničen. Konec koncev, razen če setActionCommand ()
se pri nekaterih imenuje izrecno Vrvica
argument (ne null), besedilo gumba je šteje za ukaz dejanja s samim gumbom. Zakaj bi se model moral obnašati drugače?
Ko vaša koda potrebuje sklic na trenutno izbrani gumb v ButtonGroup
, morate slediti tem korakom, med katerimi noben ne vključuje klicanja getSelection ()
:
- Pokliči
getElements ()
naButtonGroup
, ki vrneNaštevanje
- Ponavljajte skozi
Naštevanje
da dobite sklic na posamezen gumb - Pokliči
isSelected ()
na vsakem gumbu, da ugotovite, ali je izbran - Vrnite sklic na gumb, ki je vrnil true
- Če potrebujete ukaz za dejanje, pokličite
getActionCommand ()
na gumbu
Če je to videti kot veliko korakov samo za sklic gumba, preberite. verjamem ButtonGroup
Izvajanje je v osnovi napačno. ButtonGroup
ohrani sklic na model izbranega gumba, kadar naj dejansko hrani sklic na sam gumb. Poleg tega od getSelection ()
pridobi metodo izbranega gumba, morda mislite, da je ustrezna metoda nastavitve setSelection ()
, ampak ni: je setSelected ()
. Zdaj, setSelected ()
ima velik problem. Njeni argumenti so a ButtonModel
in logično vrednost. Če pokličete setSelected ()
na a ButtonGroup
in podajte model gumba, ki ni del skupine in prav
kot argumente, potem ta gumb postane izbran in vsi gumbi v skupini postanejo neizbrani. Z drugimi besedami, ButtonGroup
ima možnost, da izbere ali prekliče izbiro katerega koli gumba, ki je bil poslan njegovi metodi, čeprav ta nima nič skupnega s skupino. Do tega vedenja pride, ker setSelected ()
v ButtonGroup
ne preveri, ali je ButtonModel
sklic, prejet kot argument, predstavlja gumb v skupini. In ker metoda uveljavi en izbor, dejansko prekliče izbiro lastnih gumbov, da izbere enega, ki ni povezan s skupino.
Ta določba v ButtonGroup
dokumentacija je še bolj zanimiva:
No, pravzaprav ne. Uporabite lahko kateri koli gumb, ki sedi kjer koli v vaši aplikaciji, viden ali ne, in celo onemogočen. Da, lahko celo uporabite skupino gumbov, da izberete onemogočen gumb zunaj skupine, vendar bo še vedno preklical izbor vseh gumbov. Če se želite sklicevati na vse gumbe v skupini, morate poklicati smešno getElements ()
. Kakšne povezave imajo "elementi" ButtonGroup
je kdo uganil. Ime je verjetno navdihnilo Naštevanje
metode razreda (hasMoreElements ()
in nextElement ()
), vendar getElements ()
očitno bi moral biti imenovan getButtons ()
. Skupina gumbov združuje gumbe in ne elemente.
Rešitev: JButtonGroup
Zaradi vseh teh razlogov sem hotel uvesti nov razred, ki bo odpravil napake v ButtonGroup
in uporabniku nudijo nekaj funkcionalnosti in udobja. Moral sem se odločiti, ali naj bo razred nov ali ga podedujem ButtonGroup
. Vsi prejšnji argumenti predlagajo ustvarjanje novega razreda namesto a ButtonGroup
podrazred. Vendar pa ButtonModel
vmesnik zahteva metodo setGroup ()
ki traja a ButtonGroup
prepir. Če nisem bil pripravljen ponovno uporabiti tudi modelov gumbov, je bila moja edina možnost podrazred ButtonGroup
in preglasi večino svojih metod. Ko smo že pri ButtonModel
vmesnik, opazite odsotnost imenovane metode getGroup ()
.
Še eno vprašanje, ki ga nisem omenil, je to ButtonGroup
interno hrani sklice na svoje gumbe v a Vektor
. Tako po nepotrebnem sinhronizira Vektor
režijske stroške, ko bi moral uporabiti ArrayList
, ker razred sam po sebi ni varen in je Swing vseeno enojni navoj. Vendar zaščitena spremenljivka gumbi
je razglašen za Vektor
tipa in ne Seznam
kot bi lahko pričakovali dober slog programiranja. Tako spremenljivke nisem mogel ponovno uporabiti kot ArrayList
; in ker sem hotel poklicati super.add ()
in super.remove ()
, Spremenljivke superklase nisem mogel skriti. Zato sem vprašanje opustil.
Predlagam razred JButtonGroup
, v tonu z večino imen razreda Swing. Razred preglasi večino metod v ButtonGroup
in nudi dodatne metode priročnosti. Shrani sklic na trenutno izbrani gumb, ki ga lahko pridobite s preprostim klicem getSelected ()
. Zahvale gredo ButtonGroup
je slaba izvedba, lahko bi poimenoval svojo metodo getSelected ()
, od getSelection ()
je metoda, ki vrne model gumba.
Sledijo JButtonGroup
metode.
Najprej sem naredil dve modifikaciji dodaj ()
metoda: Če je gumb, ki ga želite dodati, že v skupini, se metoda vrne. Tako skupini ne morete dodati gumba več kot enkrat. S ButtonGroup
, lahko ustvarite JRadioButton
in ga dodajte 10-krat v skupino. Klicanje getButtonCount ()
nato vrne 10. To se ne bi smelo zgoditi, zato ne dovolim podvojenih referenc. Če je bil dodani gumb že izbran, postane izbrani gumb (to je privzeto vedenje v ButtonGroup
, kar je smiselno, zato ga nisem preglasil). The selectedButton
spremenljivka je sklic na trenutno izbrani gumb v skupini:
javni void add (gumb AbstractButton) gumbi. vsebuje (gumb)) return; super.add (gumb); če je (getSelection () == button.getModel ()) selectedButton = button;
Preobremenjeni dodaj ()
metoda v skupino doda celo vrsto gumbov. Uporabno je, če sklice gumbov shranite v matriko za obdelavo blokov (tj. Nastavitev meja, dodajanje poslušalcev dejanj itd.):
javni void add (gumbi AbstractButton []) {if (gumbi == null) return; za (int i = 0; i
Naslednja dva načina odstranijo gumb ali vrsto gumbov iz skupine:
javna praznina odstranite (gumb AbstractButton) {if (gumb! = null) {if (izbrani gumb == gumb) selectedButton = null; super.remove (gumb); }} javna void odstranitev (gumbi AbstractButton []) {if (gumbi == null) return; za (int i = 0; i
V nadaljevanju prvi setSelected ()
metoda vam omogoča, da nastavite stanje izbire gumba tako, da namesto modela prenesete referenco gumba. Druga metoda preglasi ustrezno setSelected ()
v ButtonGroup
da zagotovite, da lahko skupina izbere ali prekliče izbor gumba, ki pripada skupini:
javna void setSelected (gumb AbstractButton, izbrano logično ime) {if (gumb! = niče && gumbi.se nahaja (gumb)) {setSelected (button.getModel (), izbrano); če je (getSelection () == button.getModel ()) selectedButton = button; }} javna void setSelected (model ButtonModel, izbrana logična vrednost) {AbstractButton button = getButton (model); if (buttons.contens (button)) super.setSelected (model, izbran); }
The getButton ()
metoda pridobi referenco na gumb, katerega model je podan. setSelected ()
uporablja to metodo za pridobivanje gumba, ki je izbran glede na njegov model. Če model, ki je poslan metodi, pripada gumbu zunaj skupine, nič
se vrne. Ta metoda bi morala obstajati v ButtonModel
izvajanja, žal pa ne:
public AbstractButton getButton (model ButtonModel) {Iterator it = buttons.iterator (); medtem ko (it.hasNext ()) {AbstractButton ab = (AbstractButton) it.next (); če (ab.getModel () == model) vrne ab; } vrni null; }
getSelected ()
in isSelected ()
so najpreprostejše in verjetno najbolj uporabne metode JButtonGroup
razred. getSelected ()
vrne sklic na izbrani gumb in isSelected ()
preobremeni istoimensko metodo v ButtonGroup
za sklic gumba:
public AbstractButton getSelected () {return selectedButton; } javno boolean isSelected (gumb AbstractButton) {gumb za vrnitev == selectedButton; }
Ta metoda preveri, ali je gumb del skupine:
javna logična vrednost vsebuje (gumb AbstractButton) {vrni gumbe. vsebuje (gumb); }
Pričakovali bi imenovano metodo getButtons ()
v ButtonGroup
razred. Vrne nespremenljiv seznam, ki vsebuje sklice na gumbe v skupini. Nespremenljiv seznam preprečuje dodajanje ali odstranjevanje gumbov, ne da bi šel skozi metode skupine gumbov. getElements ()
v ButtonGroup
ne samo, da ima popolnoma nenadihnjeno ime, ampak vrne tudi Naštevanje
, ki je zastarel razred, ki ga ne bi smeli uporabljati. Okvir zbirk ponuja vse, kar potrebujete, da se izognete naštevanju. Takole je getButtons ()
vrne nespremenljiv seznam:
javni seznam getButtons () {return Collections.unmodifiableList (gumbi); }
Izboljšajte ButtonGroup
The JButtonGroup
razred ponuja boljšo in priročnejšo alternativo gugalnici ButtonGroup
razreda, hkrati pa ohranil vso funkcionalnost superrazreda.
Preberite več o tej temi
- Prenesite izvorno kodo, ki spremlja ta članek
//images.techhive.com/downloads/idge/imported/article/jvw/2003/09/jw-javatip142.zip
- Domača stran tečajev Java Foundation Classa podjetja Sun Microsystems
//java.sun.com/products/jfc/
- Java 2 Platform, Standard Edition (J2SE) 1.4.2 API dokumentacija
//java.sun.com/j2se/1.4.2/docs/api/
- Razred ButtonGroup
//java.sun.com/j2se/1.4.2/docs/api/javax/swing/ButtonGroup.html
- Oglejte si vse prejšnje Java Nasveti in oddajte svojega
//www.javaworld.com/columns/jw-tips-index.shtml
- Prebrskajte AWT / nihanje odsek JavaWorld 's Aktualni indeks
//www.javaworld.com/channel_content/jw-awt-index.shtml
- Prebrskajte Temeljni razredi odsek JavaWorld 's Aktualni indeks
//www.javaworld.com/channel_content/jw-foundation-index.shtml
- Prebrskajte Oblika uporabniškega vmesnika odsek JavaWorld 's Aktualni indeks
//www.javaworld.com/channel_content/jw-ui-index.shtml
- Obiščite forum JavaWorld
//www.javaworld.com/javaforums/ubbthreads.php?Cat=&C=2
- Prijavite se za JavaWorld 'brezplačna tedenska glasila po e-pošti
//www.javaworld.com/subscribe
To zgodbo "Java Nasvet 142: potiskanje JButtonGroup" je prvotno objavil JavaWorld.