Programmēšana

Java padoms 142: JButtonGroup nospiešana

Swing ir daudz noderīgu klašu, kas atvieglo grafiskā lietotāja interfeisa (GUI) izstrādi. Dažas no šīm nodarbībām tomēr netiek labi īstenotas. Viens šādas klases piemērs ir PogaGrupa. Šajā rakstā ir paskaidrots, kāpēc PogaGrupa ir slikti izstrādāts un piedāvā aizstājēju klasi, JButtonGroup, kas manto no PogaGrupa un novērš dažas tās problēmas.

Piezīme: Šī raksta avota kodu varat lejupielādēt vietnē Resursi.

ButtonGroup caurumi

Šeit ir izplatīts Swing GUI izstrādes scenārijs: veidojat veidlapu, lai apkopotu datus par vienumiem, kurus kāds ievadīs datu bāzē vai saglabās failā. Veidlapā var būt tekstlodziņi, izvēles rūtiņas, pogas un citi logrīki. Jūs izmantojat PogaGrupa klasē, lai sagrupētu visas radiopogas, kurām nepieciešama viena atlase. Kad veidlapas noformējums ir gatavs, sākat ieviest veidlapas datus. Jūs sastopaties ar radio pogu komplektu, un jums jāzina, kura grupas poga tika izvēlēta, lai jūs varētu saglabāt atbilstošo informāciju datu bāzē vai failā. Jūs tagad esat iestrēdzis. Kāpēc? The PogaGrupa klase nedod jums atsauci uz grupā pašlaik izvēlēto pogu.

PogaGrupa ir getSelection () metode, kas atgriež izvēlētās pogas modeli (kā PogaModelis tips), nevis pati poga. Tagad tas varētu būt labi, ja jūs varētu iegūt pogas atsauci no tā modeļa, bet nevarat. The PogaModelis interfeiss un tā ieviešanas klases neļauj izgūt pogas atsauci no tā modeļa. Tad ko tu dari? Jūs skatāties PogaGrupa dokumentāciju un skatīt getActionCommand () metodi. Jūs atceraties, ka, ja jūs instantiate a JRadioButton ar Stīga blakus pogai parādītajam tekstam un pēc tam zvanāt getActionCommand () uz pogas atgriežas konstruktora teksts. Jūs domājat, ka joprojām varat turpināt kodu, jo pat tad, ja jums nav pogas atsauces, jums vismaz ir tā teksts un jūs joprojām zināt izvēlēto pogu.

Nu, pārsteigums! Jūsu kods darbības laikā saplīst ar a NullPointerException. Kāpēc? Tā kā getActionCommand () iekšā PogaModelis atgriežas nulle. Ja jūs derēsit (kā es to izdarīju) getActionCommand () rada to pašu rezultātu neatkarīgi no tā, vai to izsauc uz pogas vai modeļa (kas notiek ar daudzi citas metodes, piemēram, isSelected (), isEnabled ()vai getMnemonic ()), tu zaudēji. Ja jūs skaidri nezvanāt setActionCommand () uz pogas jūs nenosaka darbības komandu tās modelī, un metode getter atgriežas nulle modelim. Tomēr getter metode dara atgrieziet pogas tekstu, kad tiek izsaukta poga. Šeit ir getActionCommand () metode AbstractButton, ko mantoja visas Swing pogu klases:

 publiskā virkne getActionCommand () {virkne ac = getModel (). getActionCommand (); if (ac == null) {ac = getText (); } atgriezties ac; } 

Šī neatbilstība komandas komandas iestatīšanā un iegūšanā nav pieļaujama. Jūs varat izvairīties no šīs situācijas, ja setText () iekšā AbstractButton iestata modeļa darbības komandu pogas tekstā, ja darbības komanda ir nulle. Galu galā, ja vien setActionCommand () tiek skaidri saukts ar dažiem Stīga arguments (nav nulle), pogas teksts ir uzskatīja darbības komandu ar pašu pogu. Kāpēc modelim būtu jāuzvedas savādāk?

Kad kodam ir nepieciešama atsauce uz pašreiz izvēlēto pogu PogaGrupa, jums ir jāveic šādas darbības, no kurām neviena nav saistīta ar zvanīšanu getSelection ():

  • Zvaniet getElements () ieslēgts PogaGrupa, kas atgriež an Uzskaitīšana
  • Atkārtot caur Uzskaitīšana lai iegūtu atsauci uz katru pogu
  • Zvaniet isSelected () uz katras pogas, lai noteiktu, vai tā ir atlasīta
  • Atgrieziet atsauci uz pogu, kas atgriezās kā patiesa
  • Vai arī, ja jums nepieciešama darbības komanda, zvaniet getActionCommand () uz pogas

Ja tas izskatās kā daudz darbību, lai tikai iegūtu pogas atsauci, izlasiet to. ES ticu PogaGrupaīstenošana ir principiāli nepareiza. PogaGrupa saglabā atsauci uz izvēlētās pogas modeli, kad tai faktiski jāsaglabā atsauce uz pašu pogu. Turklāt kopš getSelection () izgūst izvēlētās pogas metodi, jūs domājat, ka atbilstošā iestatītāja metode ir setSelection (), bet tā nav: tā ir setSelected (). Tagad, setSelected () ir liela problēma. Tās argumenti ir: PogaModelis un būla. Ja piezvani setSelected () uz PogaGrupa un nodot pogas modeli, kas nav grupas dalībnieks, un taisnība kā argumenti, šī poga kļūst atlasīta, un visas grupas pogas kļūst neatlasītas. Citiem vārdiem sakot, PogaGrupa ir tiesības atlasīt vai atcelt jebkuru pogu, kas nodota tās metodei, kaut arī pogai nav nekāda sakara ar grupu. Šī uzvedība rodas tāpēc, ka setSelected () iekšā PogaGrupa nepārbauda, ​​vai PogaModelis atsauce, kas saņemta kā arguments, apzīmē pogu grupā. Tā kā metode nodrošina vienotu izvēli, tā faktiski atceļ savas pogas, lai izvēlētos vienu, kas nav saistīta ar grupu.

Šis noteikums PogaGrupa dokumentācija ir vēl interesantāka:

Lai notīrītu pogu grupu, pogu programmatiski nevar izslēgt, lai to izslēgtu. Lai parādītu “neviens nav atlasīts”, pievienojiet grupai neredzamu radiopogu un pēc tam programmatiski atlasiet šo pogu, lai izslēgtu visas parādītās radiopogas. Piemēram, parasto pogu ar etiķeti “neviens” var pieslēgt, lai izvēlētos neredzamo radiopogu.

Nu nav īsti. Varat izmantot jebkuru pogu, sēžot jebkurā lietojumprogrammas vietā, redzams vai nē, un pat invalīds. Jā, jūs pat varat izmantot pogu grupu, lai ārpus grupas izvēlētos atspējotu pogu, un tā joprojām atcels visas pogas. Lai iegūtu atsauces uz visām grupas pogām, jums jāsauc smieklīgi getElements (). Ar ko saistīti "elementi" PogaGrupa ir kāds minējums. Nosaukumu, iespējams, iedvesmoja Uzskaitīšana klases metodes (hasMoreElements () un nextElement ()), bet getElements () skaidri vajadzēja nosaukt getButtons (). Poga grupē pogas, nevis elementus.

Risinājums: JButtonGroup

Visu šo iemeslu dēļ es vēlējos ieviest jaunu klasi, kas novērš kļūdas PogaGrupa un nodrošina lietotājam zināmu funkcionalitāti un ērtības. Man bija jāizlemj, vai klasei vajadzētu būt jaunai klasei vai mantot PogaGrupa. Visi iepriekšējie argumenti iesaka izveidot jaunu klasi, nevis a PogaGrupa apakšklase. Tomēr PogaModelis saskarnei nepieciešama metode setGroup () kas prasa a PogaGrupa arguments. Ja vien es nebiju gatavs atjaunot arī pogu modeļus, mana vienīgā iespēja bija apakšklase PogaGrupa un ignorē lielāko daļu tās metožu. Runājot par PogaModelis saskarni, pamaniet, ka nav metodes, ko sauc getGroup ().

Viens cits jautājums, kuru neesmu minējis, ir tāds PogaGrupa iekšēji saglabā atsauces uz savām pogām a Vector. Tādējādi tas nevajadzīgi tiek sinhronizēts Vectorkad tas jāizmanto ArrayList, tā kā klase pati par sevi nav vītņota, un Swing tik un tā ir ar vienu vītni. Tomēr aizsargātais mainīgais pogas tiek pasludināts par Vector tips, un ne Saraksts kā jūs varētu sagaidīt no laba programmēšanas stila. Tādējādi es nevarēju atkārtoti ieviest mainīgo kā ArrayList; un tāpēc, ka es gribēju piezvanīt super.add () un super.remove (), Es nevarēju noslēpt superklases mainīgo. Tāpēc es atteicos no šī jautājuma.

Es ierosinu klasi JButtonGroup, saskaņā ar lielāko daļu Swing klases nosaukumu. Klase ignorē lielāko daļu metožu PogaGrupa un nodrošina papildu ērtības metodes. Tas saglabā atsauci uz pašlaik izvēlēto pogu, kuru varat iegūt, vienkārši piezvanot uz getSelected (). Pateicoties PogaGrupaslikta ieviešana, es varētu nosaukt savu metodi getSelected (), kopš getSelection () ir metode, kas atgriež pogas modeli.

Pēc ir JButtonGroupmetodes.

Pirmkārt, es veicu divas modifikācijas pievienot () metode: ja pievienojamā poga jau atrodas grupā, metode atgriežas. Tādējādi jūs nevarat pievienot pogu grupai vairāk nekā vienu reizi. Ar PogaGrupa, varat izveidot JRadioButton un pievienojiet to grupai 10 reizes. Zvanīšana getButtonCount () pēc tam atgriezīsies 10. Tam nevajadzētu notikt, tāpēc es neatļauju dublēt atsauces. Pēc tam, ja pievienotā poga tika izvēlēta iepriekš, tā kļūst par izvēlēto pogu (tā ir noklusējuma uzvedne sistēmā Windows) PogaGrupa, kas ir saprātīgi, tāpēc es to nepārcēlu). The izvēlēta poga mainīgais ir atsauce uz pašlaik izvēlēto pogu grupā:

public void add (pogas AbstractButton poga). satur (poga)) atgriešanās; super.add (poga); if (getSelection () == button.getModel ()) selectedButton = poga; 

Pārslogota pievienot () metode grupai pievieno veselu pogu masīvu. Tas ir noderīgi, ja blokā apstrādājat masīvā glabājat pogu atsauces (t.i., robežu iestatīšana, darbību klausītāju pievienošana utt.):

public void add (AbstractButton [] pogas) {if (pogas == null) atgriežas; par (int i = 0; i

Pogas vai pogu masīvu no grupas noņem no šīm divām metodēm:

public void noņemt (poga AbstractButton) {if (poga! = null) {if (izvēlētaButton == poga) selectedButton = null; super.noņemt (poga); }} public void remove (AbstractButton [] pogas) {if (pogas == null) atgriežas; par (int i = 0; i

Turpmāk pirmais setSelected () metode ļauj iestatīt pogas izvēles stāvokli, nododot pogas atsauci, nevis tās modeli. Otrā metode ignorē atbilstošo setSelected () iekšā PogaGrupa lai pārliecinātos, ka grupa var atlasīt vai atcelt tikai pogu, kas pieder grupai:

public void setSelected (poga AbstractButton, izvēlēta būla vērtība) {if (poga! = null && pogas. satur (poga)) {setSelected (button.getModel (), izvēlēts); if (getSelection () == button.getModel ()) selectedButton = poga; }} public void setSelected (ButtonModel model, Boolean selected) {AbstractButton button = getButton (model); ja (pogas. satur (poga)) super.setSelected (modelis, izvēlēts); } 

The getButton () metode izgūst atsauci uz pogu, kuras modelis ir dots. setSelected () izmanto šo metodi, lai izgūtu izvēlēto pogu, ņemot vērā tā modeli. Ja metodei nodotais modelis pieder pogai ārpus grupas, nulle tiek atgriezta. Šai metodei vajadzētu būt PogaModelis ieviešana, bet diemžēl tā nav:

public AbstractButton getButton (ButtonModel modelis) {Iterator it = pogas.iterator (); while (it.hasNext ()) {AbstractButton ab = (AbstractButton) it.next (); if (ab.getModel () == modelis) atgriež ab; } return null; } 

getSelected () un isSelected () ir vienkāršākās un, iespējams, visnoderīgākās JButtonGroup klasē. getSelected () atgriež atsauci uz izvēlēto pogu un isSelected () operētājsistēmā pārslogo tā paša nosaukuma metodi PogaGrupa ņemt atsauci uz pogu:

public AbstractButton getSelected () {return selectedButton; } public boolean isSelected (poga AbstractButton) {atgriešanās poga == selectedButton; } 

Šī metode pārbauda, ​​vai poga ir daļa no grupas:

public Boolean satur (poga AbstractButton) {atgriešanas pogas. satur (poga); } 

Jūs varētu sagaidīt metodi ar nosaukumu getButtons () iekšā PogaGrupa klasē. Tas atgriež nemaināmu sarakstu, kurā ir atsauces uz grupas pogām. Nemainīgais saraksts novērš pogu pievienošanu vai noņemšanu, neizlaižot pogu grupas metodes. getElements () iekšā PogaGrupa ne tikai nav pilnīgi iedvesmots vārds, bet arī atgriež Uzskaitīšana, kas ir novecojusi klase, kuru nevajadzētu izmantot. Kolekciju ietvars nodrošina visu nepieciešamo, lai izvairītos no uzskaitīšanas. Tas ir kā getButtons () atgriež nemaināmu sarakstu:

public List getButtons () {return Collections.unmodifiableList (pogas); } 

Uzlabot ButtonGroup

The JButtonGroup klase piedāvā labāku un ērtāku alternatīvu Swing PogaGrupa klasē, vienlaikus saglabājot visu superklases funkcionalitāti.

Daniels Tofans ir kā pēcdoktorants Asociācijas nodaļā Ņujorkas Valsts universitātē, Stony Brook. Viņa darbs ir saistīts ar kursu vadības sistēmas pamatdaļas izstrādi ar pielietojumu ķīmijā. Viņš ir Sun 2 sertificēts programmētājs Java 2 platformā un ir ieguvis doktora grādu ķīmijā.

Uzziniet vairāk par šo tēmu

  • Lejupielādējiet avota kodu, kas pievienots šim rakstam

    //images.techhive.com/downloads/idge/imported/article/jvw/2003/09/jw-javatip142.zip

  • Sun Microsystems Java Foundation Classes mājas lapa

    //java.sun.com/products/jfc/

  • Java 2 Platform, Standard Edition (J2SE) 1.4.2 API dokumentācija

    //java.sun.com/j2se/1.4.2/docs/api/

  • PogaGrupa klase

    //java.sun.com/j2se/1.4.2/docs/api/javax/swing/ButtonGroup.html

  • Skatīt visu iepriekšējo Java padomi un iesniedziet savu

    //www.javaworld.com/columns/jw-tips-index.shtml

  • Pārlūkot AWT / šūpoles sadaļa JavaWorld 's Aktuālais rādītājs

    //www.javaworld.com/channel_content/jw-awt-index.shtml

  • Pārlūkot Fonda nodarbības sadaļa JavaWorld 's Aktuālais rādītājs

    //www.javaworld.com/channel_content/jw-foundation-index.shtml

  • Pārlūkot Lietotāja saskarnes dizains sadaļa JavaWorld 's Aktuālais rādītājs

    //www.javaworld.com/channel_content/jw-ui-index.shtml

  • Apmeklējiet JavaWorld forumu

    //www.javaworld.com/javaforums/ubbthreads.php?Cat=&C=2

  • Pierakstieties JavaWorld 's bezmaksas iknedēļas e-pasta biļeteni

    //www.javaworld.com/subscribe

Šo stāstu "Java Padoms 142: JButtonGroup virzīšana" sākotnēji publicēja JavaWorld.

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