![]() |
![]() |
Start på kapittel om grafiske brukergrensesnitt |
Uttegning av grafikk, inklusive visning av bilder, bør generelt gjøres
på en egen flate som er reservert for nettopp dette. For dersom vi tegner ut
grafikk på en flate der vi også plasserer grafiske skjermkomponenter
(knapper, tekstfelter, etc.), så kan det lett føre til konflikter ved at
skjermkomponentene blir tegnet oppå grafikken, eller omvendt. Egne tegneflater
får vi definert i form av subklasser til
JPanel
.
Det er da i de fleste tilfeller nødvendig å redefinere metoden
public void paintComponent( Graphics g )
som arves (indirekte) fra klassen JComponent
.
NB! Første instruksjon i den redefinerte metoden må være
super.paintComponent( g );
Følger vi ikke denne regelen, risikerer vi at uttegning på skjermen ikke blir riktig.
Lar vi være å redefinere paintComponent
-metoden, kan vi imidlertid
likevel kunne få tegnet ut grafikk på panelet, forutsatt at vi får tak i panelets
såkalte grafikk-kontekst. Denne teknikken er brukt i eksempel 3 nedenfor.
Klassene JFrame
og JApplet
er ikke
subklasser til JComponent
. (JFrame
er subklasse til
Frame
og JApplet
er subklasse til Applet
.)
Disse klassene arver derfor ikke noen metode
paintComponent
, men derimot metoden paint
, som vi
kjenner fra tidligere. Når vi definerer subklasser til JFrame
og
JApplet
, er det derfor paint
-metoden vi må redefinere
for å få tegnet ut direkte på vindus- eller appletflata det vi ønsker av grafikk.
Det skal aldri gjøres direkte kall på verken paint
eller paintComponent
. Det blir automatisk gjort kall på metodene
når komponenten som de tilhører blir tegnet ut på skjermen. Dersom
vi ønsker at det skal foretas ny
uttegning, gjør vi kall på metoden repaint
. Den vil i sin tur
gjøre kall på paint
eller paintComponent
, avhengig
av hvilken type komponent kallet på repaint
skjer ifra.
JPanel
-objekterEt JPanel
-objekt har i utgangspunktet en utstrekning på bare
10 piksler hver vei. Når vi bruker det som container, vil det automatisk bli
gjort akkurat stort nok til å romme de komponentene vi legger inn i det. Men
når vi bare bruker det som en tegneflate, legges ingen komponenter inn. Vi
må derfor på annen måte sørge for at det får ønsket størrelse. Én måte
er å bruke en layout-manager som strekker det ut slik at det fyller opp et
bestemt felt. Dette vil for eksempel skje når vi plasserer det i en container
ved bruk av BorderLayout
. En annen mulighet er å redefinere
metoden getPreferredSize
på følgende måte:
public Dimension getPreferredSize() { return new Dimension( b, h ); }
der b
og h
angir bredde og høyde i det antall
piksler som vi ønsker for hver av dem. (Metoden blir arvet fra klassen java.awt.Component
.)
Eventuelt kan vi også redefinere metodene getMinimumSize
og
getMaximumSize
på tilsvarende måte.
En tredje mulighet for å sette størrelse er å gjøre kall på metoden
setPreferredSize
for panelet, eventuelt også på metodene
setMinimumSize
og setMaximumSize
. Alle disse skal som
parameter ha et objekt av type Dimension
som angir ønsket dimensjon.
Det opprettes som vist i metoden getPreferredSize
ovenfor.
Klassen
Blink
som er gjengitt
nedenfor definerer et tegnepanel der det blir tegnet ut en figur som ser ut som
en blink, som vist på følgende bilde:
I driverklassen
Blinkframviser
for programmet
blir det opprettet et panel av den definerte typen. Det blir lagt inn som
eneste komponent i vinduet som er vist på bildet ovenfor.
(Eksemplet er tilpasset fra læreboka til Lewis & Loftus: Java Software
Solutions.)
1 import javax.swing.JPanel; 2 import java.awt.*; 3 4 public class Blink extends JPanel 5 { 6 private final int MAXBREDDE = 300, ANTRINGER = 5, RINGBREDDE = 25; 7 8 // Setter bakgrunnsfarge og størrelse. 9 public Blink() 10 { 11 setBackground (Color.cyan); 12 setPreferredSize (new Dimension(300,300)); 13 } 14 15 // Tegner blinken. 16 public void paintComponent(Graphics tegneflate) 17 { 18 super.paintComponent (tegneflate); 19 20 int x = 0, y = 0, diameter = MAXBREDDE; 21 22 tegneflate.setColor (Color.white); 23 24 for (int teller = 0; teller < ANTRINGER; teller++) 25 { 26 // veksler mellom farger 27 if (tegneflate.getColor() == Color.black) 28 tegneflate.setColor (Color.white); 29 else 30 tegneflate.setColor (Color.black); 31 32 tegneflate.fillOval (x, y, diameter, diameter); 33 34 diameter -= (2 * RINGBREDDE); 35 x += RINGBREDDE; 36 y += RINGBREDDE; 37 } 38 39 // Tegner den røde disken i sentrum. 40 tegneflate.setColor (Color.red); 41 tegneflate.fillOval (x, y, diameter, diameter); 42 } 43 }
Klassen
Kastepanel
er en modifikasjon
av Blink
som ble brukt i forrige program. Klassen blir
brukt i programmet
Kasteprogram.java
som gir
et vindu som vist på følgende bilde:
Programmet er ment å skulle simulere kast på blinken. Det blir gjort ved at
det for hvert nytt kast blir beregnet en tilfeldig posisjon på panelet. I
denne posisjonen blir det tegnet en liten sirkel som er avgrenset av svart strek og
fylt med gul farge innenfor den svarte streken. Kode for dette ligger i
metoden kastPåBlink
. Fargene for sirkelen er valgt slik at det skal
oppnås kontrast mot
underlaget uavhengig av hvor på panelet sirkelen blir tegnet. Sirkelen må imidlertid
tegnes først etter at selve blinken er tegnet opp, ellers vil den bli overtegnet
av blinken. Hver gang det skal foretas et nytt kast blir hele panelet tegnet ut
på nytt, slik at eventuelt tidligere treffpunkt blir fjernet. Koden for
det nye panelet er gjengitt nedenfor.
1 import javax.swing.JPanel; 2 import java.awt.*; 3 4 public class Kastepanel extends JPanel 5 { 6 private final int MAXBREDDE = 300, ANTRINGER = 5, RINGBREDDE = 25; 7 private final int BALLDIAMETER = 10; 8 private boolean kast = false; 9 10 // Setter bakgrunnsfarge og størrelse for tegnepanelet. 11 public Kastepanel() 12 { 13 setBackground(Color.cyan); 14 setPreferredSize(new Dimension(300,300)); 15 } 16 17 // Tegner blinken. 18 public void paintComponent(Graphics tegneflate) 19 { 20 super.paintComponent(tegneflate); 21 22 int x = 0, y = 0, diameter = MAXBREDDE; 23 24 tegneflate.setColor(Color.white); 25 26 for (int count = 0; count < ANTRINGER; count++) 27 { 28 // veksler mellom farger 29 if (tegneflate.getColor() == Color.black) 30 tegneflate.setColor (Color.white); 31 else 32 tegneflate.setColor (Color.black); 33 34 tegneflate.fillOval (x, y, diameter, diameter); 35 36 diameter -= (2 * RINGBREDDE); 37 x += RINGBREDDE; 38 y += RINGBREDDE; 39 } 40 41 // Tegner den røde disken i sentrum. 42 tegneflate.setColor (Color.red); 43 tegneflate.fillOval (x, y, diameter, diameter); 44 45 if ( kast ) 46 { 47 kastPåBlink( tegneflate ); 48 kast = false; 49 } 50 } 51 52 public void nyttKast() 53 { 54 kast = true; 55 repaint(); 56 } 57 58 public void kastPåBlink( Graphics g ) 59 { 60 int x = (int) (Math.random() * (MAXBREDDE - BALLDIAMETER) ); 61 int y = (int) (Math.random() * (MAXBREDDE - BALLDIAMETER) ); 62 g.setColor( Color.BLACK ); 63 g.drawOval( x, y, BALLDIAMETER, BALLDIAMETER ); 64 g.setColor( Color.YELLOW ); 65 g.fillOval( x+1, y+1, BALLDIAMETER-2, BALLDIAMETER-2 ); 66 } 67 }
Koden for vinduet
Kastevindu
er gjengitt
nedenfor. Det blir der opprettet et panel av den definerte typen. Panelet blir
lagt inn i senter-posisjon på vinduets contentPane. (Vi bruker default-layouten
for dette, som er BorderLayout
.) I sør-posisjon blir det lagt inn en
knapp som kan brukes til å foreta nye kast. Knappens lytteobjekt gjør kall
på panelets metode nyttKast
som sørger for at panelet blir tegnet ut
på nytt med et simulert treff i en ny posisjon (som imidlertid også kan være
en bom!).
1 import javax.swing.*; 2 import java.awt.*; 3 import java.awt.event.*; 4 5 public class Kastevindu extends JFrame 6 { 7 private Kastepanel blink; 8 private JButton kasteknapp; 9 10 public Kastevindu() 11 { 12 super( "Kaste på blink" ); 13 blink = new Kastepanel(); 14 kasteknapp = new JButton( "Kast på blinken" ); 15 kasteknapp.addActionListener( new Knappelytter() ); 16 Container c = getContentPane(); 17 c.add( blink, BorderLayout.CENTER ); 18 c.add( kasteknapp, BorderLayout.PAGE_END ); 19 } 20 21 private class Knappelytter implements ActionListener 22 { 23 public void actionPerformed( ActionEvent e ) 24 { 25 if ( e.getSource() == kasteknapp ) 26 blink.nyttKast(); 27 } 28 } 29 }
Flere eksempler på bruk av tegnepanel finnes i avsnittet Musehendelser og lytteobjekter for mus.
Copyright © Kjetil Grønning, revidert av Eva Hadler Vihovde 2014
![]() |
![]() |
Start på kapittel om grafiske brukergrensesnitt |