Innholdsoversikt for programutvikling
JTabbedPane
(fanekort)BoxLayout
JTable
JEditorPane
JToolBar
Action
-objekterCaretListener
JFormattedTextField
-objekterJSpinner
-objekterDe vanligste og mest grunnleggende komponentene brukt i grafiske brukergrensesnitt er behandlet i notatet Grafiske brukergrensesnitt, grunnleggende komponenter. I dette notatet blir bruken av noen mer spesialiserte komponenter forklart.
Av menyer finnes det to typer: menyer som befinner seg på en menylinje,
og popp-opp-menyer. Menyer av den første typen åpner seg når vi klikker
på menynavnet (eller bruker et tilknyttet tastealternativ). Menyer av den
andre typen åpner seg når vi klikker med høyre museknapp mens musepekeren
er på komponenten som menyen tilhører. Vi kan ha menyer både i vanlige
vinduer (definert av subklasser til JFrame
) og i
appleter (definert av subklasser til JApplet
).
For å opprette menyer, trenger vi objekter av flere forskjellige
typer. Klassene som definerer objektene er subklasser til
JComponent
og ligger på følgende måte i forhold til denne:
JComponent
JMenuBar
JPopupMenu
JSeparator
JAbstractButton
JMenuItem
JMenu
JCheckBoxMenuItem
JRadioButtonMenuItem
I denne oppstillingen betyr innrykk subklasse av den klasse som står rett før innrykket.
En menylinje er et
JMenuBar
-objekt. Den
inneholder en eller flere menyer:
JMenu
-objekter.
Hver meny (JMenu
-objekt) inneholder et eller flere
menyalternativer:
JMenuItem
-objekter. Hvert
menyalternativ (JMenuItem
-objekt) legges inn i menyen
ved bruk av menyobjektets add
-metode. Objekter av type
JSeparator
kan vi legge inn i menyen (ved bruk av
add
-metoden) for å få horisontale skillestreker mellom
menyalternativer, i tilfelle vi ønsker å ha det.
Vi ser at menyalternativer kan være av flere forskjellige
undertyper i tillegg til den vanlige typen
JMenuItem
:
JMenu
gir en undermenyJCheckBoxMenuItem
gir en avkrysningsboksJRadioButtonMenuItem
gir en radioknappVi legger dessuten merke til at alle klassene som definerer
menyalternativer er subklasser til klassen
AbstractButton
. De er med andre ord en type knapp,
knapper som til vanlig er skjult, men som kommer til syne når vi åpner
menyen.
Menyer skal stå på en menylinje — et
JMenuBar
-objekt
— og må legges inn på menylinja ved bruk av
menylinjeobjektets add
-metode. Rekkefølgen for menyene
på menylinja (fra venstre mot høyre) blir lik rekkefølgen for kall på
add
-metoden for å legge dem inn.
Menylinja må i sin tur
legges inn i vindusobjektet ved kall på vindusobjektets metode
setJMenuBar( menylinje );
(der menylinje
er JMenuBar
-objektet).
Legg for øvrig merke til at vi ikke bruker noen layout-manager
for å plassere menylinja (og heller ikke for å få plassert menyene
på menylinja).
Valg av et menyalternativ genererer en ActionEvent
.
Menyalternativer må derfor knyttes til lytteobjekter av type
ActionListener
. Når det gjelder menyalternativer av type
avkrysningsboks, så genererer de også ItemEvent
'er. For
slike menyalternativer er det derfor mer vanlig å bruke lytter av type
ItemListener
.
Menyalternativer kan, slik som knapper generelt, knyttes til tastaturalternativer, slik at vi kan aktivere menyene ved hjelp av tastaturet som alternativ til å bruke musa. For menyalternativer er tastaturalternativene av to forskjellige typer. Den ene typen brukes til å åpne menyer, navigere i dem ved hjelp av piltaster, og gjøre valg ved å trykke på returtasten. Slike tastaturalternativer settes ved å skrive kode av type
menyalternativ.setMnemonic( tegn );
Dette er tilsvarende kode som vi har brukt tidligere for å sette tastaturalternativ for knapper. Som parameter bør brukes en bokstav som finnes i navnet på menyalternativet, fortrinnsvis første bokstav. Denne bokstaven vil da bli understreket når menyen eller menyalternativet vises på skjermen, slik at brukeren kan se hva tastaturalternativet er. For å velge alternativet, må da Alt-tasten holdes nede mens vi trykker på vedkommende tast. Dersom det dreier seg om en meny eller undermeny, vil denne som følge av dette åpne seg. Er det derimot en av de vanlige typene menyalternativ, vil virkningen være den samme som om vi hadde valgt dette ved å klikke på det med musa.
Den andre typen tastaturalternativ er en hurtigtast for å velge vedkommende menyalternativ uten å gå veien om å åpne menyen som inneholder alternativet. For å sette slik hurtigtast, skriver vi kode på denne form:
menyalternativ.setAccelerator( KeyStroke.getKeyStroke( KeyEvent.VK_S, ActionEvent.CTRL_MASK ) );
Slik det står her, er det Ctrl-S som blir hurtigtasten.
Ønsker vi at det skal være Alt-tasten istedenfor Ctrl-tasten som skal
brukes for å få hurtigtast, skriver vi
ActionEvent.ALT_MASK
istedenfor
ActionEvent.CTRL_MASK
. Hvilken tast som skal brukes
i tillegg til én av disse, står vi selvsagt fritt i å velge
(ved å skrive noe annet enn VK_S
for den virtuelle
tastaturkoden).
Hurtigtaster kan ikke brukes til å åpne menyer eller undermenyer. De kan bare brukes til å velge menyalternativer som ikke representerer en meny eller en undermeny. Dersom vi har satt hurtigtast for et menyalternativ, vil det bak navnet på dette bli skrevet ut på skjermen hva som er hurtigtasten. Brukes koden som står ovenfor, vil det stå Ctrl-S bak navnet på menyalternativet, slik at brukeren kan se hva det er.
Programvinduet
Menyvindu
er det gjengitt kode for nedenfor. Et liknende eksempel finnes i
Fig. 25.5 i 9. utgave av læreboka til Deitel & Deitel. Her er det vist
en fornorsket utgave av dette. Dessuten er det til menyalternativene for
valg av fontfamilie knyttet følgende hurtigtaster:
Ctrl-S: Serif |
Ctrl-M: Monospaced |
Ctrl-A: SansSerif |
Det er i kildekoden skrevet kommentarer som indikerer rollen til de
enkelte delene av programkoden. Driverklasse for programmet finnes i fila
Menytest.java
.
Bildene nedenfor viser to forskjellige tilstander til programvinduet.
1 import java.awt.*; 2 import java.awt.event.*; 3 import javax.swing.*; 4 5 public class Menyvindu extends JFrame 6 { 7 8 private Color farger[] = {Color.black, Color.blue, Color.red, 9 Color.green}; 10 private JRadioButtonMenuItem[] fargevalg, fontvalg; 11 private JCheckBoxMenuItem[] fontstiler; 12 private JLabel demotekst; 13 private ButtonGroup fontgruppe, fargegruppe; 14 private int stil; 15 16 public Menyvindu() 17 { 18 super("Bruk av menyer"); 19 20 // setter opp filmeny og dens alternativer 21 JMenu filmeny = new JMenu("Fil"); 22 filmeny.setMnemonic('F'); 23 24 // setter opp Om...-menyalternativet 25 JMenuItem infovalg = new JMenuItem("Om..."); 26 infovalg.setMnemonic('O'); 27 infovalg.addActionListener( 28 new ActionListener() 29 { 30 // viser en meldingsboks når brukeren velger Om... 31 32 public void actionPerformed(ActionEvent e) 33 { 34 JOptionPane.showMessageDialog(Menyvindu.this, 35 "Dette er et eksempel\npå bruk av menyer", 36 "Om", JOptionPane.PLAIN_MESSAGE); 37 } 38 }); 39 filmeny.add(infovalg); 40 41 // setter opp Avslutt-menyalternativet 42 JMenuItem avslutt = new JMenuItem("Avslutt"); 43 avslutt.setMnemonic('A'); 44 avslutt.addActionListener( 45 new ActionListener() 46 { 47 // avslutter programmet når brukeren velger dette 48 // alternativet 49 50 public void actionPerformed(ActionEvent e) 51 { 52 System.exit(0); 53 } 54 }); 55 filmeny.add(avslutt); 56 57 // oppretter menylinje og plasserer den i vinduet 58 JMenuBar menylinje = new JMenuBar(); 59 setJMenuBar(menylinje); 60 menylinje.add(filmeny); 61 62 // oppretter Format-meny, dens undermenyer og menyalternativer 63 JMenu formatmeny = new JMenu("Format"); 64 formatmeny.setMnemonic('r'); 65 66 // oppretter undermeny for fargevalg 67 String fargenavn[] = {"Svart", "Blå", "Rød", "Grønn"}; 68 JMenu fargemeny = new JMenu("Skriftfarge"); 69 fargemeny.setMnemonic('S'); 70 71 fargevalg = new JRadioButtonMenuItem[fargenavn.length]; 72 fargegruppe = new ButtonGroup(); 73 Menyvalglytter menylytter = new Menyvalglytter(); 74 75 // oppretter menyalternativer av type radioknapper for fargevalg 76 for (int i = 0; i < fargenavn.length; i++) 77 { 78 fargevalg[ i] = new JRadioButtonMenuItem(fargenavn[ i]); 79 fargemeny.add(fargevalg[ i]); 80 fargegruppe.add(fargevalg[ i]); 81 fargevalg[ i].addActionListener(menylytter); 82 } 83 84 fargevalg[ 0].setSelected(true); 85 86 // tilføyer fargemenyen og en skillestrek til formatmenyen 87 formatmeny.add(fargemeny); 88 formatmeny.addSeparator(); 89 90 // oppretter undermenyen for fontvalg 91 String[] fontnavn = {"Serif", "Monospaced", "SansSerif"}; 92 93 JMenu fontmeny = new JMenu("Font"); 94 fontmeny.setMnemonic('n'); 95 96 fontvalg = new JRadioButtonMenuItem[fontnavn.length]; 97 fontgruppe = new ButtonGroup(); 98 99 // oppretter menyalternativer av type radioknapper for fontvalg 100 for (int i = 0; i < fontvalg.length; i++) 101 { 102 fontvalg[ i] = new JRadioButtonMenuItem(fontnavn[ i]); 103 fontmeny.add(fontvalg[ i]); 104 fontgruppe.add(fontvalg[ i]); 105 fontvalg[ i].addActionListener(menylytter); 106 } 107 108 //Setter hurtigtaster for fontfamilie: 109 //S: Serif, M: Monospaced, A: SansSerif 110 fontvalg[ 0].setAccelerator(KeyStroke.getKeyStroke( 111 KeyEvent.VK_S, ActionEvent.CTRL_MASK)); 112 fontvalg[ 1].setAccelerator(KeyStroke.getKeyStroke( 113 KeyEvent.VK_M, ActionEvent.CTRL_MASK)); 114 fontvalg[ 2].setAccelerator(KeyStroke.getKeyStroke( 115 KeyEvent.VK_A, ActionEvent.CTRL_MASK)); 116 117 fontvalg[ 0].setSelected(true); 118 119 fontmeny.addSeparator(); 120 121 // setter opp menyalternativer for stil 122 String[] stilnavn = {"Fet", "Kursiv"}; 123 124 fontstiler = new JCheckBoxMenuItem[stilnavn.length]; 125 Stillytter stillytter = new Stillytter(); 126 127 // oppretter menyalternativer av type avkryssingsboks for 128 // valg av stil 129 for (int i = 0; i < stilnavn.length; i++) 130 { 131 fontstiler[ i] = new JCheckBoxMenuItem(stilnavn[ i]); 132 fontmeny.add(fontstiler[ i]); 133 fontstiler[ i].addItemListener(stillytter); 134 } 135 136 // tilføyer fontmenyen til formatmenyen 137 formatmeny.add(fontmeny); 138 139 // tilføyer formatmenyen til menylinja 140 menylinje.add(formatmeny); 141 142 // setter opp labelen for visning av teksteksempel 143 demotekst = new JLabel("Teksteksempel", SwingConstants.CENTER); 144 demotekst.setForeground(farger[ 0]); 145 demotekst.setFont(new Font("Serif", Font.PLAIN, 72)); 146 147 getContentPane().setBackground(Color.cyan); 148 getContentPane().add(demotekst, BorderLayout.CENTER); 149 150 setSize(600, 200); 151 setVisible(true); 152 } // slutt på konstruktør 153 154 // definerer lytteobjekt for menyalternativer 155 private class Menyvalglytter implements ActionListener 156 { 157 // behandler valg av tekstfarge og skriftfont 158 public void actionPerformed(ActionEvent e) 159 { 160 boolean ferdig = false; 161 for (int i = 0; i < fargevalg.length && !ferdig; i++) 162 { 163 if (fargevalg[ i].isSelected()) 164 { 165 demotekst.setForeground(farger[ i]); 166 ferdig = false; 167 } 168 } 169 170 ferdig = true; 171 for (int i = 0; i < fontvalg.length && !ferdig; i++) 172 { 173 if (e.getSource() == fontvalg[ i]) 174 { 175 demotekst.setFont(new Font( 176 fontvalg[ i].getText(), stil, 72)); 177 ferdig = false; 178 } 179 } 180 181 repaint(); 182 } 183 } // slutt på klasse Menyvalglytter 184 185 // definerer lytteobjekt for menyvalg av type avkryssingsboks 186 private class Stillytter implements ItemListener 187 { 188 // behandler valg av fontstil 189 public void itemStateChanged(ItemEvent e) 190 { 191 stil = 0; 192 193 // sjekker om det er valgt fete typer 194 if (fontstiler[ 0].isSelected()) 195 { 196 stil += Font.BOLD; 197 } 198 199 // sjekker om det er valgt kursiv 200 if (fontstiler[ 1].isSelected()) 201 { 202 stil += Font.ITALIC; 203 } 204 205 demotekst.setFont(new Font( 206 demotekst.getFont().getName(), stil, 72)); 207 208 repaint(); 209 } 210 } // slutt på klasse Stillytter 211 }
Popp-opp-menyer er objekter av type
JPopupMenu
.
Vi oppretter popp-opp-menyer på liknende måte som andre menyer, men
popp-opp-menyer har ikke noe menynavn:
JPopupMenu sprettOpp = new JPopupMenu();
Menyalternativer legger vi inn på samme måte som for vanlige menyer:
JMenuItem alternativ = new JMenuItem( "..." ); alternativ.addActionListener( lytter ); sprettOpp.add( alternativ );
For øvrig så er virkemåten til vanlige menyer på en menylinje den at når vi aktiverer menyen ved å klikke på den med musa eller ved å bruke et tilknyttet tastaturalternativ, slik at menyen åpner seg, så er det egentlig en popp-opp-meny som blir vist og som inneholder menyalternativene.
Den vanlige virkemåten for popp-opp-menyer på Windows-plattformer
er at vi ønsker at popp-opp-menyen skal vises når vi klikker med høyre
museknapp mens musepekeren står på den komponenten (for eksempel vinduet)
som menyen tilhører. For å få til dette, er det ikke nødvendig å
knytte menyen til komponenten på noen spesiell måte.
Isteden må vi for komponenten definere en muselytter som gjør kall på
menyens show
-metode når menyen skal vises. Siden dette
skal skje når en museknapp trykkes ned, er det
mousePressed
-metoden som må inneholde den nødvendige koden:
public void mousePressed( MouseEvent e ) { if ( e.isPopupTrigger() ) // ble høyre museknapp trykket ned? { sprettOpp.show( e.getComponent(), e.getX(), e.getY() ); } }
NB! Implementasjonen av metoden
isPopupTrigger
er plattformavhengig. Derfor bør den
kalles opp både av mousePressed
og av
mouseReleased
for å sikre at popp-opp-menyen virker
som den skal på alle plattformer. På (iallfall noen) Windows-plattformer
er det bare for mouseReleased
at
isPopupTrigger()
returnerer true
. Vi må med
andre ord implementere mouseReleased
på tilsvarende måte:
public void mouseReleased( MouseEvent e ) { if ( e.isPopupTrigger() ) // ble høyre museknapp trykket ned? { sprettOpp.show( e.getComponent(), e.getX(), e.getY() ); } }
Sprett-opp-menyen vil, slik som andre menyer, lukke seg igjen automatisk så snart vi har gjort er menyvalg.
Programvinduet
Poppoppvindu
som blir definert av koden nedenfor, viser et tomt vindu som i utgangspunktet har hvit
bakgrunnsfarge. Når man holder musepekeren over vinduet og høyreklikker
musa, spretter det opp en meny som kan brukes til å velge en annen
bakgrunnsfarge for vinduet. (Programmet er en fornorsket versjon av programmet
som finnes i Fig. 25.7 i 9. utgave av læreboka til Deitel & Deitel.)
Driverklasse for programmet finnes i fila
Poppopptest.java
.
Følgende to bilder viser to tilstander av programvinduet.
1 import java.awt.*; 2 import java.awt.event.*; 3 import javax.swing.*; 4 5 //Demonstrasjon av popp-opp-meny 6 public class Poppoppvindu extends JFrame 7 { 8 private JRadioButtonMenuItem fargevalg[]; 9 private final Color farger[] = {Color.BLUE, Color.YELLOW, Color.RED}; 10 private JPopupMenu poppoppmeny; 11 12 public Poppoppvindu() 13 { 14 super("Bruk av popp-opp-meny"); 15 16 Radioknapplytter lytter = new Radioknapplytter(); 17 String fargenavn[] = {"Blå", "Gul", "Rød"}; 18 19 // setter opp popp-opp-menyen med dens fargevalg 20 ButtonGroup fargegruppe = new ButtonGroup(); 21 poppoppmeny = new JPopupMenu(); 22 fargevalg = new JRadioButtonMenuItem[3]; 23 24 // oppretter hvert menyalternativ og tilføyer det til popp-opp- 25 // menyen; registrerer også lytteobjekt for hvert menyalternativ 26 for (int i = 0; i < fargevalg.length; i++) 27 { 28 fargevalg[ i] = new JRadioButtonMenuItem(fargenavn[ i]); 29 poppoppmeny.add(fargevalg[ i]); 30 fargegruppe.add(fargevalg[ i]); 31 fargevalg[ i].addActionListener(lytter); 32 } 33 34 getContentPane().setBackground(Color.WHITE); 35 36 // registrerer muselytter for vinduet 37 addMouseListener(new Muselytter()); 38 39 setSize(300, 200); 40 setVisible(true); 41 } // end constructor PopupTest 42 43 // Definerer en muselytter som viser popp-opp-menyen ved klikk på 44 // høyre museknapp. 45 private class Muselytter extends MouseAdapter 46 { 47 public void mousePressed(MouseEvent e) 48 { 49 sjekkOmMenySkalVises(e); 50 } 51 52 public void mouseReleased(MouseEvent e) 53 { 54 sjekkOmMenySkalVises(e); 55 } 56 57 // Egendefinert metode som sjekker om det ble klikket på høyre 58 // museknapp. Viser i så fall popp-opp-menyen. 59 private void sjekkOmMenySkalVises(MouseEvent e) 60 { 61 if (e.isPopupTrigger()) 62 { 63 poppoppmeny.show(e.getComponent(), e.getX(), e.getY()); 64 } 65 } 66 } 67 68 private class Radioknapplytter implements ActionListener 69 { 70 public void actionPerformed(ActionEvent e) 71 { 72 // sjekker hvilket menyalternativ som ble valgt 73 for (int i = 0; i < fargevalg.length; i++) 74 { 75 if (e.getSource() == fargevalg[ i]) 76 { 77 getContentPane().setBackground(farger[ i]); 78 return; 79 } 80 } 81 } 82 } 83 }
Copyright © Kjetil Grønning og Eva Hadler Vihovde, revidert 2014
![]() |
Start på kapittel om spesialiserte komponenter for grafiske brukergrensesnitt |