![]() |
![]() |
Start på kapittel om grafiske brukergrensesnitt |
En listeboks -
JList<E>
-objekt
- kan brukes til å velge ett eller
flere alternativer fra en gruppe. Det vanligste er at alternativene vises i
listeboksen i form av tekststrenger, men en kan ha lister av hvilke som helst
typer objekter. Det mest aktuelle utenom tekststrenger, er ikoner. Blir det brukt
andre typer objekter, kreves det ekstra programmering for å bestemme hvordan
objektene skal vises på skjermen. (Tilsvarende gjelder for kombobokser.)
Følgende bilde viser hva vi får dersom det blir brukt en listeboks istedenfor
en komboboks til å velge bilde med i programeksemplet som ble brukt i notatet om
kombobokser. Programkoden for det nye vinduet kommer vi tilbake til etter
å ha tatt for oss en del generelt om bruken av listebokser.
Fra og med javaversjon 7 er JList<E>
-klassen definert som
en parametrisert klasse. Fordelen med dette er stort sett
at man slipper litt typekonvertering i forbindelse
med programmering av lytteobjekt, samt at det foretas mer typekontroll under
kompilering. Det går fortsatt an å bruke
klassen uten typeparameter, men en metode som da er aktuell å bruke for flervalgslistebokser,
er nå markert som foreldet. Som erstatning er det kommet til en ny metode.
Dette blir kommentert nærmere under omtalen av
slike listebokser nedenfor. I eksemplene i det følgende blir det brukt typeparameter.
For å opprette en listeboks med String
-alternativer, kan vi
gjøre slik (uttrykt i pseudo-kode):
String[] alternativer = { ... };
JList<String> listeboks = new JList<>(alternativer);
eller
JList<String> listeboks = new JList<>();
listeboks.setListData( alternativer );
Som det ble beskrevet under omtalen av MVC-arkitektur, er det slik at listeinnholdet (og innholdet til komponenter generelt) blir lagret i en såkalt modell, i dette tilfelle en listemodell. For de enkle komponentene som vi har brukt hittil har det ikke vært nødvendig å jobbe direkte på modellen, men det må vi faktisk gjøre for å kunne programmere listebokser, iallfall dersom det dreier seg om noe som går utover det aller enkleste. Første eksemplet på det får vi når vi skal ta for oss flervalgslistebokser nedenfor. Når vi oppretter listebokser som forklart ovenfor, så vil det automatisk bli generert en listemodell som det seinere ikke går an å endre på. Dersom vi ønsker å kunne endre innholdet, må vi opprette vår egen listemodell. Det blir gjort i eksemplet om flervalgslistebokser nedenfor.
Siden vi for listebokser må jobbe direkte mot modellen når det gjelder innholdet,
så finnes det for listebokser heller ingen metode addItem
, slik som
det ble nevnt for kombobokser.
Vi kan bestemme hvor mange alternativer som skal være synlige samtidig i en listeboks:
listeboks.setVisibleRowCount( antall );
der int
-parameteren antall
angir antallet.
Default-verdi er 8.
Dersom det er flere alternativer enn antall synlige samtidig, bør
listeboksen være utstyrt med skrollefelt. Det blir ikke gjort
automatisk, slik det er tilfelle med kombobokser. Enklest er det å legge
listeboksen inn i en JScrollPane
:
JScrollPane skrolleliste = new JScrollPane( listeboks );
Det vil i så fall være skrollelista vi må add'e til containeren som skal inneholde listeboksen.
Metoden setSelectionMode
brukes til å bestemme om lista av alternativer
i listeboksen skal være envalgsliste eller flervalgsliste:
listeboks.setSelectionMode( type );
der parameteren type
kan ha én av følgende verdier:
ListSelectionModel.SINGLE_SELECTION ListSelectionModel.SINGLE_INTERVAL_SELECTION ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
Default er flervalgsliste av den sist nevnte typen. Den midterste verdien gir en listeboks der flere alternativer kan velges i et sammenhengende intervall. Brukes den siste verdien, får vi en listeboks der de valgte alternativene kan ligge vilkårlig. Nærmere detaljer angående bruk av flervalgslister skal vi se på seinere.
JList
-objekter genererer hendelser av type
ListSelectionEvent
. Disse kan fanges opp av et lytteobjekt av
type ListSelectionListener
. Dette vil gjøre kall på metoden
public void valueChanged( ListSelectionEvent e ) { ... }
For å definere et slikt lytteobjekt må vi derfor skrive en klasse som
implementerer interface ListSelectionListener
ved at den gir en
definisjon av den nevnte metoden.
Lytteobjektet knyttes til JList
-objektet ved kall på metoden
addListSelectionListener( < lytteobjekt > );
Museklikk på et alternativ i listeboksen genererer faktisk tre hendelser av
type ListSelectionEvent
: Når museknappen går ned, er det én
hendelse for å indikere at det gamle alternativet ble av-valgt og én
for å indikere at det nye ble valgt. På begge disse vil
e.getValueIsAdjusting()
(der e
er parameteren i valueChanged
) returnere
true
som indikasjon på at valget ikke er fullført ennå. Når
museknappen slippes opp, genereres den tredje hendelsen. Da vil
e.getValueIsAdjusting()
returnere false
for å
indikere at valget er fullført.
JList
-klassen har ingen forhåndsprogrammert funksjonalitet
for behandling av doble museklikk. Men det er ikke så vanskelig å programmere
dette på egen hånd. Et eksempel finnes under dokumentasjonen av
JList
-klassen.
Vi skal også se på egne eksempler på dette seinere.
I tilfelle énvalgsliste kan vi finne ut hvilket listealternativ som
ble valgt ved å gjøre kall på metoden getSelectedValue
.
Returen fra denne er av den typen som er brukt som aktuell typeparameter, i tilfelle
det blir brukt typeparameter. Dersom det ikke er brukt typeparameter, vil
returen være av
type Object
og må derfor i så fall konverteres
til riktig type. I tilfelle String
-alternativer
og String
er brukt som aktuell typeparameter
kan vi derfor skrive,
når e
er ListSelectionEvent
-objektet:
JList<String> liste = (JList) e.getSource(); String alternativ = liste.getSelectedValue(); ...
Som i kombobokser er alternativene indeksert fra 0 og oppover, slik at vi
også kan få returnert indeksen for det valgte alternativ ved kall på
listeobjektets metode getSelectedIndex
. For JList
-klassen
finnes det imidlertid ingen metode svarende til metoden getItemAt(indeks)
som vi har for kombobokser. Og grunnen til dette er igjen at vi for listebokser
må jobbe direkte mot listemodellen når det gjelder innholdet.
Programmet med vindusklasse
Listeboksdemo.java
,
som er gjengitt nedenfor, er en omarbeidet versjon
av komboboks-programmet for valg av hvilken bilde-label som skal vises.
Et bilde av programvinduet ble vist ovenfor. Merk deg hvordan listeboksen
og lytteobjektet for denne er programmert. Instruksjonen
dyrevelger.setFixedCellWidth( 50 );
sikrer at listeboksen
i utgangspunktet skal bli synlig på skjermen. Uten denne blir cellenes bredde
beregnet på grunnlag av hva de inneholder. Når de ikke inneholder noe, vil
dette resultere i 0. Det finnes en tilsvarende metode for å sette høyde
på cellene i listeboksen. Den heter setFixedCellHeight
.
For begge metodene blir vedkommende dimensjon satt til det antall pixler
som parameteren angir.
Driverklasse for programmet finnes i fila
Listebokstest.java
.
Når du kjører programmet, bør du spesielt legge merke til
hva som skjer og ikke skjer når museknappen blir trykket ned og når den blir
sluppet opp igjen.
1 import java.awt.*; 2 import javax.swing.*; 3 import javax.swing.event.*; 4 5 public class Listeboksdemo extends JFrame 6 { 7 JLabel bilde; 8 9 public Listeboksdemo() 10 { 11 super( "Listedemo" ); 12 String[] dyrenavn = { "Fugl", "Katt", "Hund", "Kanin", "Gris" }; 13 14 // Oppretter liste, velger gris som startbilde 15 JList<String> dyrevelger = new JList<>( dyrenavn ); 16 dyrevelger.setVisibleRowCount( 4 ); 17 dyrevelger.setFixedCellWidth( 50 ); 18 dyrevelger.setSelectionMode( ListSelectionModel.SINGLE_SELECTION ); 19 dyrevelger.setSelectedIndex(4); 20 dyrevelger.addListSelectionListener( new ListSelectionListener() { 21 public void valueChanged( ListSelectionEvent e) 22 { 23 if ( !e.getValueIsAdjusting() ) 24 { 25 String dyrenavn = dyrevelger.getSelectedValue(); 26 bilde.setIcon(new ImageIcon( 27 getClass().getResource("bilder/" + 28 dyrenavn + ".gif"))); 29 } 30 } 31 }); 32 33 // Oppretter bilde-label 34 bilde = new JLabel(new ImageIcon( 35 getClass().getResource("bilder/" + 36 dyrenavn[dyrevelger.getSelectedIndex()] + ".gif"))); 37 Container c = getContentPane(); 38 c.setLayout( new FlowLayout() ); 39 c.add( new JScrollPane( dyrevelger ) ); 40 c.add( bilde ); 41 } 42 }
Som nevnt ovenfor, finnes det to typer av flervalgs listebokser. For typen
ListSelectionModel.SINGLE_INTERVAL_SELECTION
må alternativene
velges i et sammenhengende intervall. For å velge, klikker vi da først på
alternatavet som skal være i den ene enden av intervallet. Så holder vi
skift-tasten nede mens vi klikker på alternativet som skal være i den andre
enden av intervallet.
For å velge alternativene vi ønsker valgt når vi har en listeboks av type
ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
, så holder vi
ctrl-tasten nede mens vi klikker på de forskjellige alternativene.
For begge de nevnte typer listebokser kan vi få tak i de valgte
alternativene enten i form av en array av indekser, ved kall på metoden
getSelectedIndices
, eller i form av en List<E>
ved kall på metoden getSelectedValuesList
. Datatypen
List<E>
er den typen som er definert i Javas
Collection
-rammeverk, det vil si den som ligger i pakken
java.util
, se
beskrivelse av denne typen
under kapitlet om dette rammeverket. For å gjennomløpe en
List<E>
kan vi bruke en utvidet
for
-løkke:
List<E> utvalg = liste.getSelectedValuesList(); for (E e : utvalg) < gjør et eller annet med e >
Før javaversjon 7 kunne en få tak
i de valgte alternativene i form av
en array av
Object
-objekter, ved kall på metoden getSelectedValues
.
Men denne metoden er i javaversjon 7 markert som foreldet.
(Metoden blir brukt i Fig. 14.25 i 9. utgave av læreboka til Deitel & Deitel,
men den er altså i JDK7 markert som foreldet, se
getSelectedValues
.)
Samme enten vi velger å hente ut valgte listealternativer i form av en array
av indekser, ved bruk av metoden getSelectedIndices
, eller i form av en
List<E>
, ved bruk av metoden getSelectedValuesList
,
så er det ikke mulig å bruke det vi får returnert på en direkte måte til å endre
innhold i listeboksen, eller å få brukt det direkte til å endre innhold i en annen
listeboks. Vil vi endre innholdet, så må vi som før nevnt få tak i listemodellen og
jobbe mot denne. Framgangsmåten for dette blir nærmere forklart i det følgende.
Når vi oppretter en listeboks på den måten som ble
forklart ovenfor, vil javasystemet opprette en listemodell
som det seinere ikke er mulig å endre innholdet i. Dersom vi ønsker en listeboks
med dynamisk innhold, altså som det skal være mulig å endre under kjøring, så
må vi opprette vår egen listemodell. Den enkleste måten å gå fram på da, er å
opprette et objekt av type
DefaultListModel<E>
,
som er en subklasse til
AbstractListModel<E>
.
Det er dette alternativet som
blir brukt i eksemplet nedenfor. Det er også mulig å definere sin egen subklasse
til AbstractListModel<E>
, men da kreves det mye mer programmering
for å få det til å virke riktig.
For å opprette egen listemodell som skal inneholde String
-alternativer,
sette inn elementer i modellen, samt opprette listeboks på grunnlag av modellen,
kan vi bruke følgende instruksjoner:
DefaultListModel<String> modell = new DefaultListModel<>(); modell.addElement( "..." ); // setter inn element ... // setter inn så mange elementer vi ønsker JList<String> listeboks = new JList<>( modell );
For å få tak i listemodellen til en eksisterende listeboks, kan vi bruke
JList
-metoden getModel
. Returen fra denne er imidlertid av type
ListModel<E>
,
som er navnet på det
interface
som blir implementert av
listemodellklassene. Dette interface
spesifiserer ingen metoder for å legge til eller fjerne elementer fra listemodellen.
Derfor må vi konvertere returen til den typen vi vet at det i praksis er, nemlig
DefaultListModel
. Metoden for å sette inn element,
addElement
, er allerede nevnt ovenfor. Tilsvarende metode for å fjerne element
er
modell.removeElement( "..." ); // fjerner element
Denne framgangsmåten er brukt i følgende programeksempel.
Flervalgsliste
er gjengitt nedenfor. Den inneholder to listebokser, den første av default-typen
ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
, mens den andre er
av typen ListSelectionModel.SINGLE_INTERVAL_SELECTION
.
Ved å klikke på knappen mellom listeboksene, kan de valgte elementene i den
første listeboksen bli tilføyd til de
eksisterende elementene i den andre listeboksen, forutsatt at de ikke finnes
fra før. For å sjekke om et element finnes fra før, brukes metoden finnes
:
57 public boolean finnes( String e, JList<String> liste ) 58 { 59 ListModel<String> listemodell = liste.getModel(); 60 for ( int i = 0; i < listemodell.getSize(); i++ ) 61 if ( listemodell.getElementAt( i ).equals( e ) ) 62 return true; 63 return false; 64 }
Metoden settInnElementer
gjennomløper lista av elementer som brukeren har valgt,
sjekker om de finnes fra før av i den listeboksen de skal settes inn i, og setter dem
inn i tilfelle de ikke finnes:
66 public void settInnElementer(List<String> elementer, 67 JList<String> liste) 68 { 69 DefaultListModel<String> listemodell = 70 (DefaultListModel) liste.getModel(); 71 for ( String s : elementer ) 72 if ( !finnes( s, liste ) ) 73 listemodell.addElement( s ); 74 }
Elementer som merkes i den andre listeboksen, kan fjernes fra denne
ved å klikke på knappen for dette.
Metoden fjernElementer
fjerner fra listeboksen de elementene brukeren
har markert.
Videre er det for den andre listeboksen
definert to listemodeller. En kan skifte mellom de to listemodellene ved å
klikke på knappen for dette. Da blir metoden skiftModell
kalt opp.
Den modellen som programmet starter opp med, er
i utgangspunktet tom, mens det i den andre er lagt inn tre elementer.
Følgende bilde viser programvinduet etter at det er valgt to elementer i den
første listeboksen og disse er blitt tilføyd i den andre.
Driverklasse for programmet finnes i fila
Flervalgslistetest.java
.
1 import javax.swing.*; 2 import java.awt.*; 3 import java.awt.event.*; 4 import java.util.List; 5 6 public class Flervalgsliste extends JFrame 7 { 8 private JList<String> fargeliste, kopiliste; 9 DefaultListModel<String> modell, nymodell; //skal inneholde 10 //alternativene til kopiliste 11 private JButton kopier, skift, fjern; 12 private String fargenavn[] = 13 { "Svart", "Blå", "Cyan", "Mørk grå", "Grå", 14 "Grønn", "Lys grå", "Magenta", "Oransje", "Rosa", 15 "Rød", "Hvit", "Gul" }; 16 17 public Flervalgsliste() 18 { 19 super( "Flervalgslister" ); 20 Container c = getContentPane(); 21 c.setLayout( new FlowLayout() ); 22 fargeliste = new JList<>( fargenavn ); 23 fargeliste.setVisibleRowCount( 5 ); 24 fargeliste.setFixedCellHeight( 15 ); 25 c.add( new JScrollPane( fargeliste ) ); 26 kopier = new JButton( "Legg til i liste >>" ); 27 c.add( kopier ); 28 29 modell = new DefaultListModel<>(); 30 kopiliste = new JList<>( modell ); 31 kopiliste.setVisibleRowCount( 5 ); 32 kopiliste.setFixedCellWidth( 100 ); 33 kopiliste.setFixedCellHeight( 15 ); 34 kopiliste.setSelectionMode( 35 ListSelectionModel.SINGLE_INTERVAL_SELECTION ); 36 c.add( new JScrollPane( kopiliste ) ); 37 38 fjern = new JButton( "Fjern fra kopiliste" ); 39 c.add( fjern ); 40 41 nymodell = new DefaultListModel<>(); 42 nymodell.addElement("Grønn"); 43 nymodell.addElement("Blå"); 44 nymodell.addElement("Rød"); 45 46 skift = new JButton( "Skift modell" ); 47 c.add( skift ); 48 49 Knappelytter lytter = new Knappelytter(); 50 kopier.addActionListener( lytter ); 51 skift.addActionListener( lytter ); 52 fjern.addActionListener( lytter ); 53 setSize( 600, 120 ); 54 setVisible( true ); 55 } 56 57 public boolean finnes( String e, JList<String> liste ) 58 { 59 ListModel<String> listemodell = liste.getModel(); 60 for ( int i = 0; i < listemodell.getSize(); i++ ) 61 if ( listemodell.getElementAt( i ).equals( e ) ) 62 return true; 63 return false; 64 } 65 66 public void settInnElementer(List<String> elementer, 67 JList<String> liste) 68 { 69 DefaultListModel<String> listemodell = 70 (DefaultListModel) liste.getModel(); 71 for ( String s : elementer ) 72 if ( !finnes( s, liste ) ) 73 listemodell.addElement( s ); 74 } 75 76 public void fjernElementer( List<String> elementer, 77 JList<String> liste ) 78 { 79 DefaultListModel<String> listemodell = 80 (DefaultListModel) liste.getModel(); 81 for (String s : elementer) 82 listemodell.removeElement( s ); 83 } 84 85 public void skiftModell( JList<String> liste ) 86 { 87 if ( liste.getModel() != nymodell ) 88 liste.setModel( nymodell ); 89 else 90 liste.setModel( modell ); 91 } 92 93 private class Knappelytter implements ActionListener 94 { 95 public void actionPerformed( ActionEvent e ) 96 { 97 if ( e.getSource() == kopier ) 98 { 99 // adderer valgte verdier til kopiliste 100 List<String> utvalg = fargeliste.getSelectedValuesList(); 101 settInnElementer( utvalg, kopiliste ); 102 } 103 else if ( e.getSource() == fjern ) 104 { 105 // fjerner valgte verdier fra kopiliste 106 List<String> utvalg = kopiliste.getSelectedValuesList(); 107 fjernElementer( utvalg, kopiliste ); 108 } 109 else if ( e.getSource() == skift ) 110 skiftModell( kopiliste ); 111 } 112 } 113 }Copyright © Kjetil Grønning, revidert av Eva Hadler Vihovde 2014
![]() |
![]() |
Start på kapittel om grafiske brukergrensesnitt |