![]() |
![]() |
Start på kapittel om spesialiserte komponenter for grafiske brukergrensesnitt |
JFormattedTextField
-objekterPropertyChangeListener
Subklassen
JFormattedTextField
til JTextField
definerer et såkalt formatert tekstfelt. Et formatert tekstfelt gjør det
mulig å spesifisere hva som skal oppfattes som lovlige tegn i tekstfeltet og
ignorere andre tegn. Et JFormattedTextField
tilføyer en
formaterer og en verdi (av objekttype) til egenskapene
som arves fra JTextField
. Det finnes forskjellige typer
formaterere. Formatereren foretar konvertering mellom feltets nevnte verdi
og hva som vises på skjermen, som er tekstfeltets tekst.
Og motsatt: Det som skrives i tekstfeltet vil formatereren
forsøke å konvertere til ny verdi for tekstfeltet (uten at vi trenger å legge
inn spesielle
try-catch
-instruksjoner).
Ved å bruke de
formatererne som finnes i klassebiblioteket, kan vi for eksempel definere
formaterte tekstfelter som kan vise og lese inn datoer og tallverdier på det
format som er standard på vedkommende sted (det vil si i Norge for vårt
vedkommende). Det er også mulig å sette opp masker som definerer hva som er
lovlige tegn i hver posisjon i tekstfeltet, slik at vi for eksempel kan
lese inn og vise telefonnumre eller fødselsnumre i et bestemt format.
Som eksempel på bruk av formaterte tekstfelter skal vi ta for oss et program som står i The Java Tutorials. Programmet er en enkel "lånekalkulator", der det er formaterte tekstfelter for lånebeløp, rentefot, løpetid og månedlig lånekostnad. Vi ser først på hvordan vi kan opprette formaterere.
Den abstrakte klassen
Format
har de to konkrete subklassene
DateFormat
og
NumberFormat
for formatering av
henholdsvis datoer og tall, begge på en slik måte at det tilpasses det som
er standard på vedkommende sted (det vil si i Norge for oss). Den første av
disse brukes for øvrig i notatet
Dato og tid. Vi kan også
bruke klassen
SimpleDateFormat
som er omtalt i samme notat. Enkleste
måten å få opprettet formateringsobjekt på, er å bruke en av verktøymetodene
som disse klassene har, og deretter eventuelt tilpasse dette objektet.
Som eksempel på dette skal vi ta for oss de tallformatene som brukes av
det kommende programeksemplet.
NumberFormat amountFormat = NumberFormat.getNumberInstance(); //Gir korrekt formatering av tall, med korrekt gruppeseparator og //desimaltegn, inntil 3 desimaler. Eksempel: 1 234 567,5 NumberFormat percentFormat = NumberFormat.getNumberInstance(); percentFormat.setMinimumFractionDigits(3); //Gir alltid minst 3 desimaler. Eksempel: 7,500 NumberFormat paymentFormat = NumberFormat.getCurrencyInstance(); //Gir korrekt formatering av pengebeløp. Eksempel: kr 1 398,43
Når vi har fått opprettet det formateringsobjektet vi ønsker å bruke, får vi opprettet et formatert tekstfelt som bruker denne formatereren ved å bruke formateringsobjektet som konstruktørparameter:
JFormattedTextField f = new JFormattedTextField(formaterer);
Det er imidlertid også mulig å bruke default-konstruktør og standardformaterer i tilfelle vi ikke har behov for å tilpasse formatereren til spesielle ønsker:
JFormattedTextField standardfelt = new JFormattedTextField();
Når vi nå setter for eksempel en heltallsverdi for tekstfeltet, så vil denne bli formatert ved bruk av en standardformaterer for heltall. På denne måten er det gjort for løpetiden for det kommende programeksemplet med den nevnte lånekalkulatoren:
numPeriodsField = new JFormattedTextField(); numPeriodsField.setValue(new Integer(numPeriods)); numPeriodsField.setColumns(10);
Som nevnt tidligere, har et formatert tekstfelt både en tekst
(den som vises i tekstfeltet, tilsvarende som for
JTextField
) og en verdi (som settes på grunnlag
av teksten). Dette er to forskjellige egenskaper for tekstfeltet, og som regel
vil oppdatering av tekstfeltets verdi være forsinket i forhold til oppdatering
av teksten. Mens brukeren skriver input i tekstfeltet, vil tekstegenskapen
endre seg, mens verdiegenskapen ikke endrer seg før endringene er såkalt
bekreftet (engelsk: committed). Det skjer dersom brukeren trykker på
returtasten mens tekstfeltet har fokus (markøren er i feltet), eller dersom
tekstfeltet mister fokus (for eksempel ved at markøren flyttes til et annet
felt).
Det finnes imidlertid to forskjellige metoder som kan endre
verdien til et formatert tekstfelt: setValue
og
commitEdit
. Metoden setValue
setter verdien til den
verdi som er aktuell parameter ved metodekallet. Denne kan teknisk sett være et hvilket som
helst Object
, men det må være av en type som formatereren kan
konvertere til en streng. Ellers vil det oppstå en
IllegalArgumentException
.
Metoden commitEdit
setter verdien til det objekt som
formatereren tolker som representert av feltets tekst. Hvordan
dette virker i praksis når det befinner seg ugyldige tegn i feltet
(for eksempel i en tekst som skal representere et tall), kan en se ved å
prøve ut det følgende programeksemplet. Metoden commitEdit
blir
kalt opp automatisk i disse to tilfellene:
setFocusLostBehavior
til å spesifisere at noe annet skal
skje når feltet mister fokus.)Når det blir satt ny verdi for det formaterte tekstfeltet, vil feltets tekst bli oppdatert til å reflektere den nye verdien. Hvordan verdien vises, avgjøres av formatereren.
Merk at selv om et formatert tekstfelt arver metodensetText
fra JTextField
, så brukes denne metoden
vanligvis ikke for formaterte tekstfelter. Brukes den, vil feltets tekst
bli oppdatert, men ikke dets verdi.
For å hente ut verdien til et formatert tekstfelt, bruker vi dets
getValue
-metode. For å være sikker på at verdien reflekterer
feltets tekst, kan vi først gjøre kall på commitEdit
(uten
parameter). Siden getValue
returnerer et Object
,
er det nødvendig å konvertere det til den type som brukes for feltets
verdi. For eksempel:
Date dato = (Date) datofelt.getValue();
PropertyChangeListener
Ovenfor er det forklart i hvilke tilfeller verdien til et formatert
tekstfelt vil endre seg. Endringen kan for eksempel ha skjedd som følge av
at brukeren har skrevet noe i feltet og trykket returtast.
Dersom vi ønsker at noe skal skje som følge av denne endringen, bruker vi ikke
lytter av type ActionListener
, slik vi gjør for vanlige tekstfelter,
men derimot lytter av type
PropertyChangeListner
.
For en slik må vi implementere metoden
public void propertyChange(PropertyChangeEvent e)
Det finnes to måter vi kan bruke for å knytte en
PropertyChangeListner
til et formatert tekstfelt. En mulighet er
å bruke den måten som vi er vant med for andre typer lyttere:
felt.addPropertyChangeListner(lytter);
Da må vi være klar over at lytteobjektet blir varslet når det skjer
endringer i en hvilken som helst av de såkalte bundne egenskapene til feltet.
(I tillegg til verdi, er det slikt som font, gjennomsiktighet, ramme, etc.)
I propertyChange
-metoden kan vi få tak i navnet på den egenskapen
som har endret seg ved å gjøre kall på
PropertyChangeEvent
-objektets
getPropertyName
-metode:
public void propertyChange(PropertyChangeEvent e) { String navn = e.getPropertyName(); if (navn.equals("value")) // verdi-egenskapen har endret seg ... }
Som alternativ til dette kan vi bruke den andre måten for å knytte
PropertyChangeListner
til et formatert tekstfelt. Vi spesifiserer
da hvilken egenskap det skal lyttes på endringer av. Er det endringer av
feltets verdi vi vil lytte på, skriver vi da
felt.addPropertyChangeListner("value", lytter);
Det er denne måten som brukes i følgende programeksempel.
FormattedTextFieldDemo
har et programvindu som ved oppstart
ser ut som vist på dette bilde.
Programmet har fire formaterte tekstfelter, de tre første editerbare. For feltet som viser løpetid brukes det standardformaterer, bestemt av feltets verdi. Feltet opprettes på følgende måte:
65 numPeriodsField = new JFormattedTextField(); 66 numPeriodsField.setValue(new Integer(numPeriods)); 67 numPeriodsField.setColumns(10); 68 numPeriodsField.addPropertyChangeListener("value", this);
For de tre andre feltene blir det definert formaterer. Det gjøres av
metoden setUpFormats
som ser slik ut:
181 //Create and set up number formats. These objects also 182 //parse numbers input by user. 183 private void setUpFormats() 184 { 185 amountFormat = NumberFormat.getNumberInstance(); 186 187 percentFormat = NumberFormat.getNumberInstance(); 188 percentFormat.setMinimumFractionDigits(3); 189 190 paymentFormat = NumberFormat.getCurrencyInstance(); 191 }
De definerte formatene brukes som konstruktørparametre når de formaterte tekstfeltene blir opprettet. Koden for dette ser ut slik:
54 //Create the text fields and set them up. 55 amountField = new JFormattedTextField(amountFormat); 56 amountField.setValue(new Double(amount)); 57 amountField.setColumns(10); 58 amountField.addPropertyChangeListener("value", this); 59 60 rateField = new JFormattedTextField(percentFormat); 61 rateField.setValue(new Double(rate)); 62 rateField.setColumns(10); 63 rateField.addPropertyChangeListener("value", this); 70 paymentField = new JFormattedTextField(paymentFormat); 71 paymentField.setValue(new Double(payment)); 72 paymentField.setColumns(10); 73 paymentField.setEditable(false); 74 paymentField.setForeground(Color.red);
Panelet som de formaterte tekstfeltene ligger i, fungerer også som
PropertyChangeListener
for de tre editerbare feltene.
Koden som implementerer lytteobjektet ser slik ut:
103 /** 104 * Called when a field's "value" property changes. 105 */ 106 public void propertyChange(PropertyChangeEvent e) 107 { 108 Object source = e.getSource(); 109 if (source == amountField) 110 { 111 amount = ((Number) amountField.getValue()).doubleValue(); 112 } 113 else if (source == rateField) 114 { 115 rate = ((Number) rateField.getValue()).doubleValue(); 116 } 117 else if (source == numPeriodsField) 118 { 119 numPeriods = ((Number) numPeriodsField.getValue()).intValue(); 120 } 121 122 double payment = computePayment(amount, rate, numPeriods); 123 paymentField.setValue(new Double(payment)); 124 }
Det brukes ingen annen type lytteobjekt for feltene, altså ingen
ActionListener
. Vi ser at innlesing skjer ved bruk av feltets
getValue
-metode, det brukes ikke getText
.
Og det er ikke nødvendig med noe
try-catch
.
Hver gang det blir lest inn en ny verdi, blir det
foretatt ny beregning av månedlig kostnad for lånet (som er et annuitetslån),
og denne verdien blir skrevet ut i det ikke-editerbare feltet. Kjør programmet
og prøv deg fram med å skrive inn forskjellige verdier i feltene, gyldige og
ugyldige, og legg merke til hva som skjer. Legg merke til at oppdatering skjer
enten som følge av trykk på returtast, eller ved at markøren flyttes til et
annet felt.
Copyright © Kjetil Grønning og Eva Hadler Vihovde, revidert 2014
![]() |
![]() |
Start på kapittel om spesialiserte komponenter for grafiske brukergrensesnitt |