Innholdsoversikt for programutvikling

Appleter

Appleter er programmer som er beregnet på å skulle kjøres i nettlesere som del av en nettside. Programtypen ble utviklet for å kunne gjøre nettsider interaktive, og ikke bare kunne vise statisk innhold. Den raske populariteten som java i starten fikk som programmeringsspråk, skyldtes i stor grad nettopp muligheten til å lage appleter. Java utviklet seg imidlertid raskt til å bli et generelt programmeringsspråk, slik at muligheten til å lage appleter nå bare er blitt en liten detalj. Selve ordet applet betyr "en liten applikasjon".

Programmeringsmessig er det svært liten forskjell på appleter og applikasjoner. Det går an å lage programmer som kan kjøres både som applet og som applikasjon. En applet har ingen main-metode. Isteden må den oppfylle andre formelle krav, blant annet må den være knyttet til en html-fil.

Siden hensikten med en applet er at den skal være en del av en nettside, og dermed bli vist i en nettleser, definerer den ikke noe eget vindu på skjermen. Isteden definerer den en flate innenfor nettleservinduet. Javas klassebibliotek inneholder to klasser som inneholder det nødvendige rammeverket for en applet. En applet må defineres i form av en subklasse til en av disse klassene. Den opprinnelige appletklassen heter nettopp Applet og ligger i pakken java.applet. Men i denne kan vi ikke bruke Javas swing-komponenter. Appleter blir derfor nå til dags vanligvis definert i form av en subklasse til klassen JApplet som må importeres fra pakken javax.swing. JApplet er i sin tur subklasse til Applet.

I appletklassen vår kan vi legge inn grafiske skjermkomponenter og definere lytteobjekter på nesten nøyaktig samme måte som vi gjør for vindusklasser. Men det er en viktig forskjell. For en vindusklasse definerer vi vanligvis en konstruktør der vi legger inn kode for å sette opp brukergrensesnitt. I main-metoden oppretter vi vindusobjekt og får dermed konstruktørens instruksjoner utført. For en applet er det nettleseren som oppretter appletobjektet ved hjelp av appletklassens default-konstruktør, altså den som er uten parametre. Deretter gjør den kall på appletklassens metode init. På grunn av denne virkemåten, er det for en appletklasse ikke vanlig å definere noen konstruktør — vi nøyer oss med den systemdefinerte default-konstruktøren. Isteden redefinerer vi init-metoden og plasserer der den koden som vi for vindusklasser normalt plasserer i konstruktøren.

For en applet er det noen bestemte metoder som automatisk blir kalt opp når appleten blir aktivert. Noen av dem er det aktuelt å redefinere når vi definerer vår appletklasse. Det gjelder følgende metoder:

public void init()

Metoden blir automatisk kalt opp én gang rett etter at appleten er opprettet (av nettleseren). Det er så og si alltid aktuelt å redefinere metoden og legge inn i den kode for initialisering, det vil si kode som vi ellers som regel plasserer i konstruktøren.

public void start()

Metoden blir automatisk kalt opp rett etter at init-metoden er avsluttet. Den blir også automatisk kalt opp dersom brukeren vender tilbake til nettsida som inneholder appleten, etter at brukeren har surfet innom én eller flere andre nettsider. Det er derfor aktuelt å redefinere metoden dersom det er kode som vi ønsker utført på nytt i slike tilfeller. Det kan for eksempel være å starte opp igjen en animasjon.

public void paint(Graphics g)

Metoden blir automatisk kalt opp når appleten blir aktivert, etter at init og start er utført. Den blir også automatisk kalt opp hver gang det er behov for å tegne opp igjen appletflata på nytt på skjermen, for eksempel etter at den har vært helt eller delvis dekket av et annet vindu og så blir avdekket igjen. Metoden utfører ved hjelp av appletens grafikk-kontekst, som er parameter, typiske tegneoperasjoner på appletflata. Vi skriver aldri selv kode for å gjøre direkte kall på metoden. Dersom vi av en eller annen grunn ønsker metoden utført, gjør vi isteden kall på metoden repaint(). Den vil i sin tur gjøre kall på paint.

public void stop()

Metoden blir automatisk kalt opp når brukeren forlater den nettsida som inneholder appleten. Det er derfor aktuelt å redefinere den dersom det er bestemte aktiviteter som da skal opphøre, for eksempel kjøring av en animasjon.

public void destroy()

Metoden blir kalt opp automatisk når nettleser-sesjonen blir avsluttet ved at nettleservinduet blir lukket. Metoden har som hensikt å frigjøre ressurser som er blitt bundet opp av appleten. Som regel er det ikke nødvendig å redefinere metoden. Metoden stop blir alltid automatisk kalt opp før destroy blir utført.

Javas Applet Viewer

Appleter er altså ment å være del av en nettside. Under utviklingsarbeidet med en applet, kan det likevel være ønskelig å kunne teste den ut for seg selv, uten at den inngår i noen nettside. Java inneholder derfor et program Applet Viewer som kan vise appleter i et eget vindu på skjermen, slik at vi kan teste dem ut. Dersom vi i Eclipse eller NetBeans skriver en appletklasse som forklart ovenfor og tar vanlig kjørekommando på den, vil den automatisk bli vist i Applet Viewer uten at vi har skrevet noen html-fil for den.

Eksempel 1

Følgende klasse definerer en applet som viser en liten label-tekst. Den forutsetter bruk av den såkalte contentPane-delegasjon som er definert fra og med java-versjon 1.5: add-metoden er programmert til å tilføye til appletens contentPane den komponent som er parameter. Default-layout for appletens contentPane er BorderLayout. Slik koden er skrevet nedenfor, vil det være i CENTER-posisjon at komponenten blir lagt inn.

 1 import javax.swing.JApplet;
 2 import javax.swing.JLabel;
 3
 4 public class Testapplet extends JApplet
 5 {
 6   public void init()
 7   {
 8     add( new JLabel("Testapplet", JLabel.CENTER));
 9   }
10 }

Når vi kjører denne klassen i NetBeans, får vi opp det vindu som er vist på følgende bilde.

Det er også mulig å kjøre Applet Viewer direkte fra konsollvinduets kommandolinje. Da må vi på kommandolinja skrive appletviewer etterfulgt av et mellomrom og fullt filnavn for en html-fil med en <applet>-tag for vedkommende applet. Vi skal se på hvordan en slik html-fil kan se ut.

HTML-fil med <applet>-tag

Følgende html-fil inneholder det som skal til for å kjøre appleten definert ovenfor.

<html>
  <head>
    <title>Testapplet</title>
  </head>
  <body>
    <applet code="Testapplet.class" width="300" height="100">
    </applet>
  </body>
</html>

Legg merke til at vi i <applet>-taggen spesifiserer hvilken fil som definerer appleten, samt setter bredde og høyde på den i antall piksler. Slik angivelsen av class-fil er skrevet, forutsettes det at fila ligger i samme filkatalog som html-fila. Setter vi ikke høyde og bredde riktig, vil appleten ikke bli vist. Som for vinduer, må vi ofte prøve oss litt fram for å finne en passe størrelse for appleten.

Når html-fil for appleten er skrevet og dens class-fil er riktig angitt og plassert, kan vi få kjørt appleten ved å vise vedkommende html-fil i en nettleser. Nettleseren må være oppsatt til å tillate visning av appleter. Det er ikke alle som er det. Følgende bilde viser resultatet av å vise appleten ovenfor i en nettleser.

Dersom din egen nettleser er satt opp for å vise appleter, kan du få kjørt appleten ovenfor ved å klikke på følgende link: testapplet.html.

En applet bør for øvrig testes ut i flere forskjellige nettlesere og versjoner av disse før vi legger den ut på nettet. Vi har ingen garantier for at nettleserne vil vise appleten vår på samme måte.

I eksemplet ovenfor er det i <applet>-taggen bare tatt med de attributtene som er obligatoriske for å få kjørt appleten i en nettleser. Det finnes i tillegg noen attributter som det er frivillig å ta med, men som noen ganger kan være nyttige. Det er følgende attributter:

  codebase = applet_url
  archive = arkivfil
  vspace = vertikalmarg
  hspace = horisontalmarg
  align = vindusplassering
  alt = tekstalternativ

De frivillige attributtene har følgende betydning:

Merknad: Størrelse for appleter

Som du ser av html-fila for eksemplet Testapplet ovenfor, setter vi i html-fila størrelse for appleten i antall piksler. Dette er nødvendig for å få den vist i en nettleser. Men som nevnt ovenfor, kan vi i Eclipse og NetBeans kjøre appleter uten at det er definert noen html-fil for appleten. De vil da selv sette en standardstørrelse for det vinduet som visningsprogrammet Applet Viewer viser. I eksemplet ovenfor kan du se hvor stort dette er i NetBeans. Det er klart at denne standardstørrelsen sjelden vil passe. For uttesting av appleter ved å kjøre dem i Eclipse eller NetBeans er det derfor ønskelig å få satt størrelse på annen måte. Det får vi gjort ved å bruke setSize-metoden i appletens init-metode på tilsvarende måte som i følgende eksempel.

Eksempel 2

 1 import javax.swing.JApplet;
 2 import javax.swing.JLabel;
 3 import java.awt.Dimension;
 4
 5 public class Testapplet extends JApplet
 6 {
 7   public void init()
 8   {
 9     setSize( new Dimension( 400, 100 ));
10     add( new JLabel("Testapplet", JLabel.CENTER));
11   }
12 }

Følgende bilde viser resultatet av å kjøre denne appleten i NetBeans ved bruk av Applet Viewer.

Når en applet blir kjørt i nettleser, vil den størrelsen som blir satt i init-metoden bli overstyrt av den størrelsen som settes i html-fila.

De enkle eksemplene ovenfor har ikke vært interaktive, slik at de har kunnet gjøre nettsider dynamiske. Vi skal nå ta for oss et eksempel på animasjon, der brukeren kan påvirke animasjonen.

Eksempel 3

Vi skal lage en applet som simulerer pendelbevegelse. Vi tenker oss at pendelen består av en kule opphengt fritt i en snor, slik at kula kan svinge fram og tilbake. Vi kaller pendelens utslagsvinkel, målt i radianer, for θ. (Utslagsvinkelen er vinkelen mellom pendelsnora og en loddlinje gjennom pendelsnoras opphengspunkt.) Når pendelen svinger, vil da utslagsvinelen være bestemt av formelen

θ = θo e-kt cos (ωt)

Her er

θo:maksimal utslagsvinkel
k:dempningsfaktor (på grunn av luftmotstand etc.)
ω:vinkelhastighet
t:tid

Dersom k = 0, får vi θ = θo cos (ωt).

Programmet skal tegne bilder av pendelen, et nytt bilde med pendelen i en ny posisjon hver gang animasjonsløkka blir gjennomløpt. Bildet av pendelen består av en rett linje og en fylt sirkel. Linja har ett fast endepunkt: svarende til opphengspunktet for pendelsnora. Vi må finne posisjonen for det andre endepunktet. For sirkelen må vi finne basisposisjonen som den skal tegnes fra, ny posisjon for hver gang. (Basisposisjonen er posisjonen for det øverste venstre hjørne i det omskrevne rektanglet.) Vi setter navn på de nødvendige koordinater og størrelser:

(xo, yo):koordinatene for pendelsnoras faste endepunkt
L:pendelsnoras lengde
(x, y):koordinatene for pendelsnoras bevegelige endepunkt

Da vil følgende formler gjelde:

x = xo + L sin θ
y = yo + L cos θ

Dersom vi kaller koordinatene til basisposisjonen for sirkelen ("pendelkula") for (xb, yb) og radien til sirkelen for R, så vil følgende formler gjelde:

xb = x - R(1 - sin θ)
yb = y - R(1 - cos θ)

Disse formlene må vi bruke for beregning av ny posisjon for pendelen. For å simulere tid bruker vi en heltallsvariabel som vi kan tenke på som sekund. Den øker vi med én hver gang animasjonsløkka blir gjennomløpt.

Klassen Pendel som er gjengitt nedenfor representerer en slik pendel. Lengden til pendelsnora og posisjonen for dens opphengspunkt mottas som konstruktørparametre. Dempningsfaktoren settes i utgangspunktet lik 0, men den kan endres ved hjelp av en set-metode. Metoden tegnPendel tegner pendelen i en gitt posisjon ved bruk av formlene som er omtalt ovenfor. Pendelens nye posisjon for tidspunktet t blir beregnet av metoden flytt. Dersom pendelen ikke har noen dempning, vil den svinge så lenge som appleten kjører. Dersom det er lagt inn dempning, vil de maksimale utslagene bli mindre og mindre. Det er da fornuftig å stoppe animasjonsløkka når det maksimale utslaget blir mindre enn en viss grense. Til dette formål brukes metoden svingende. Metoden nullstill har til hensikt å kunne gjøre det mulig å starte opp igjen animasjonen "på ny frisk" ved at den setter maksimal utslagsvinkel til 30 grader.

 1 import java.awt.Graphics;
 2 import javax.swing.JPanel;
 3
 4 public class Pendel extends JPanel
 5 {
 6   private int x0, y0;  //posisjon for pendelsnoras øverste ende
 7   private int x, y; //posisjon for pendelsnoras nederste ende
 8   private final int DIAM = 20;  //pendelkulas diameter
 9   private double k; //dempningsfaktor
10   private double theta0 = Math.PI / 6;  //startvinkel lik 30 grader
11   private double theta; //utslagsvinkel
12   private double omega = 7.0; //vinkelhastighet
13   private double grense = 0.005;  //nedre grense for maksimalt utslag
14   private int snorlengde; //pendelsnoras lengde
15
16   public Pendel(int xpos, int ypos, int lengde)
17   {
18     x0 = xpos;
19     y0 = ypos;
20     snorlengde = lengde;
21     k = 0;  //kjører uten dempning om ikke annet er valgt
22   }
23
24   public void setDempning(double dempningsfaktor)
25   {
26     k = dempningsfaktor;
27   }
28
29   public void paintComponent(Graphics g)
30   {
31     super.paintComponent(g);
32     tegnPendel(g);
33   }
34
35   public void tegnPendel(Graphics g)
36   {
37     double s = Math.sin(theta);
38     double c = Math.cos(theta);
39     //finner basispunkt for tegning av pendelkule:
40     int xb = x - (int) (DIAM * (1 - s) / 2);
41     int yb = y - (int) (DIAM * (1 - c) / 2);
42     g.fillOval(xb, yb, DIAM, DIAM);
43     g.drawLine(x0, y0, x, y);
44   }
45
46   //regner ut ny posisjon for pendelkula
47   public void flytt(long t)
48   {
49     theta0 *= Math.exp(-k * t / 100);
50     theta = theta0 * Math.cos(omega * t / 100);
51     x = x0 + (int) (snorlengde * Math.sin(theta));
52     y = y0 + (int) (snorlengde * Math.cos(theta));
53   }
54
55   public boolean svingende()
56   {
57     return (theta0 > grense);
58   }
59
60   public void nullstill()
61   {
62     theta0 = Math.PI / 6;
63   }
64 }

Selve appletklassen er gjengitt nedenfor. Datafeltet bps bestemmer hvor mange ganger per sekund pendelen skal tegnes på nytt i en ny posisjon, eller med andre ord: hvor mange nye bilder av pendelen per sekund. Drivverket for animasjonen er Timer-objektet klokke. Den er satt opp til å generere en ActionEvent så mange ganger hvert sekund som er bestemt av datafeltet bps. Appleten fungerer som lytteobjekt for Timeren, slik at appletens actionPerformed-metode blir kalt opp så mange ganger hvert sekund som er bestemt av datafeltet for antall bilder per sekund. Dersom pendelen er i bevegelse, øker actionPerformed-metoden tiden med én (simulering av at det har gått en bps-del av et sekund), flytter pendelposisjonen og tegner pendelen i ny posisjon. (En nærmere beskrivelse av Timer-klassen kan du finne i notatet Hva er en Timer?.)

Appletens start- og stop-metoder er programmert til å starte og stoppe animasjonen, ved at de gjør kall på metodene startAnimasjon og stoppAnimasjon. Disse metodene starter og stopper animasjonen ved kall på Timerens start- og stop-metoder.

Som tidligere nevnt, er pendelens dempningsfaktor i utgangspunktet satt til null. Brukeren har anledning til å skrive inn ønsket verdi for dempningsfaktoren i appletens tekstfelt. Når verdi leses inn og registreres, blir animasjonen nullstilt og startet opp igjen på nytt.

For pendelpanelet er det registrert en muselytter, definert av den indre klassen Muselytter. Denne gjør det mulig for brukeren å stoppe og starte animasjonen ved å klikke med en museknapp.

De to klassene som definerer appleten kan du laste ned ved å klikke på linkene Pendel.java og Pendelbevegelse.java.

  1 import java.awt.*;
  2 import java.awt.event.*;
  3 import javax.swing.*;
  4
  5 public class Pendelbevegelse extends JApplet implements ActionListener
  6 {
  7   private JTextField input, output;
  8   private Pendel pendel;
  9   private Timer klokke;
 10   private long tid;
 11   private boolean fastFryst = false;
 12   private int bps = 20; //antall bilder pr. sekund
 13   private int pauselengde = 1000 / bps; //tid mellom hvert nytt bilde
 14   private int y0 = 20;  //avstand fra øvre kant til pendelsnoras 
 15                         //festepunkt
 16
 17   public void init()
 18   {
 19     setSize(new Dimension(700, 500));
 20     JPanel np = new JPanel();
 21     np.add(new JLabel("Velg dempingsfaktor:"));
 22     input = new JTextField(4);
 23     input.addActionListener(this);
 24     np.add(input);
 25     output = new JTextField(20);
 26     output.setEditable(false);
 27     np.add(output);
 28     klokke = new Timer(pauselengde, this);
 29     klokke.setInitialDelay(0);
 30     klokke.setCoalesce(true);
 31     tid = 0L;
 32     Container c = getContentPane();
 33     c.add(np, BorderLayout.PAGE_START);
 34     Dimension dim = getSize();
 35     if (dim.height - 100 > 50)
 36     {
 37       pendel = new Pendel(dim.width / 2, y0, dim.height - 100);
 38       pendel.addMouseListener(new Muselytter());
 39       c.add(pendel, BorderLayout.CENTER);
 40     }
 41     else
 42     {
 43       output.setText("For lav applet.");
 44     }
 45   }
 46
 47   public void start()
 48   {
 49     startAnimasjon();
 50   }
 51
 52   public void stop()
 53   {
 54     stoppAnimasjon();
 55   }
 56
 57   public synchronized void startAnimasjon()
 58   {
 59     if (!fastFryst)
 60     { //starter animasjon
 61       if (!klokke.isRunning())
 62       {
 63         klokke.start();
 64       }
 65     }
 66   }
 67
 68   public synchronized void stoppAnimasjon()
 69   {
 70     if (klokke.isRunning())  //stopper animasjonstråden
 71     {
 72       klokke.stop();
 73     }
 74   }
 75
 76   public void actionPerformed(ActionEvent e)
 77   {
 78     if (e.getSource() == input)
 79     {
 80       try
 81       {
 82         double dempningsfaktor = Double.parseDouble(input.getText());
 83         pendel.setDempning(dempningsfaktor);
 84         stoppAnimasjon();
 85         pendel.nullstill();
 86         tid = 0L;
 87         pendel.flytt(tid);
 88         klokke.setInitialDelay(0);
 89         startAnimasjon();
 90       }
 91       catch (NumberFormatException ex)
 92       {
 93         output.setText("Galt tallformat. Prøv igjen!");
 94       }
 95     }
 96     else if (pendel.svingende())
 97     {
 98       pendel.flytt(tid++);
 99       pendel.repaint();
100     }
101   }
102
103   private class Muselytter extends MouseAdapter
104   {
105     public void mousePressed(MouseEvent e)
106     {
107       if (fastFryst)
108       {
109         fastFryst = false;
110         startAnimasjon();
111       }
112       else
113       {
114         fastFryst = true;
115         stoppAnimasjon();
116       }
117     }
118   }
119 }

Ved at du klikker på følgende link, skal du få kjørt apppleten i din nettleser: Kjør animasjon!.

Følgende bilde gir et øyeblikksbilde av den svingende pendelen.

Eksempel 4: Kochs snøflakkurve

Vi skal lage en applet som suksessivt kan tegne de kurvene som danner grunnlaget for den såkalte fraktalkurva som kalles Kochs snøflakkurve. Kurva framkommer ved å ta utgangspunkt i en likesidet trekant som vist på følgende bilde.

Denne trekanten skal vi kalle kurve av orden 1. For å utvikle den rekursive metoden som kan tegne kurver av høyere ordener, skal vi nå ta for oss én av sidene i denne trekanten og sette navn (x1, y1), (x5, y5) på koordinatene til endepunktene, slik det er vist på neste bilde.

For å få kurve av orden 2, blir hver av de rette linjene på kurve av orden 1 erstattet med en brukket linje tilsvarende som vist på følgende figur for den ene linja på foregående figur.

På figuren har vi navngitt de nye hjørnene med (x2, y2), (x3, y3) og (x4, y4). Hver bit av den nye, brukne linja har en lengde lik 1/3 (en tredel) av den opprinnelige, rette linja fra kurve av orden 1.

Prosessen med å danne kurver av høyere ordener fortsetter på samme måte: Hver rett linje erstattes av en brukket linje tilsvarende som ved overgangen fra orden 1 til orden 2. Neste skritt på den kurve som er vist på siste figur, vil gi følgende figur.

Det som går under navn av Kochs snøflakkurve, får vi ved å fortsette den nevnte prosessen i det uendelige. Det vi skal gjøre, er å lage en applet som suksessivt kan vise kurver av høyere og høyere ordener, inntil noen av enkeltbitene blir så små at det ikke har noen hensikt å fortsette videre på grunn av begrenset skjermoppløsning.

For å komme fram til den rekursive metoden for å tegne kurvene av forskjellige ordener, gjør vi nå følgende observasjoner:

Koordinatene for punktene med indeksverdier 2, 3 og 4 bestemmer vi på grunnlag av koordinatene for punktene med indeksverdier 1 og 5 slik at avstanden mellom to punkter som følger etter hverandre er en tredel av avstanden mellom (x1, y1) og (x5, y5). Bruk av enkel matematikk gir formlene

  x2 = x1 + (x5 - x1)/3
  y2 = y1 + (y5 - y1)/3
  x3 = (x1 + x5)/2 + 3½(y1 - y5)/6
  y3 = (y1 + y5)/2 + 3½(x5 - x1)/6
  x4 = x1 + 2(x1 + x5)/3
  y4 = y1 + 2(y1 + y5)/3

Det er klart at koordinatene x1, y1, x5, y5, samt kurvas orden, må være parametre i den rekursive metoden som skal tegne kurve av en gitt orden. Det metoden må gjøre, er å beregne koordinatene til de tre nye punktene ved å bruke formlene ovenfor. Og så må metoden tegne en kurve av orden én lavere mellom to og to punkter som følger etter hverandre. Dessuten må den, selvsagt, sjekke om det dreier seg om et basistilfelle. I følgende metode, som implementerer denne virkemåten, er det brukt konstanten

 8   private double SQ = Math.sqrt(3.0) / 6; //brukes i koordinatberegning

som inngår i to av formlene ovenfor.

21   public void tegnFraktal(int orden, int x1, int y1, int x5, int y5,
22           Graphics g)
23   {
24     if (orden == 1)
25     {
26       g.drawLine(x1, y1, x5, y5);
27     }
28     else
29     {
30       int deltaX = x5 - x1;
31       int deltaY = y5 - y1;
32       int x2 = x1 + deltaX / 3;
33       int y2 = y1 + deltaY / 3;
34       int x3 = (int) ((x1 + x5) / 2 + SQ * (y1 - y5));
35       int y3 = (int) ((y1 + y5) / 2 + SQ * (x5 - x1));
36       int x4 = x1 + deltaX * 2 / 3;
37       int y4 = y1 + deltaY * 2 / 3;
38
39       tegnFraktal(orden - 1, x1, y1, x2, y2, g);
40       tegnFraktal(orden - 1, x2, y2, x3, y3, g);
41       tegnFraktal(orden - 1, x3, y3, x4, y4, g);
42       tegnFraktal(orden - 1, x4, y4, x5, y5, g);
43     }
44   }

I programmet som skal gjøre bruk av den rekursive tegnemetoden, må vi bestemme hvilken trekant som skal være kurve av orden 1, det vil si vi må bestemme hjørnenes koordinater. Det må gjøres kall på den rekursive tegnemetoden for hver av de tre sidene i basistrekanten. Klassen KochPanel som er gjengitt nedenfor definerer et tegnepanel for kurva. Klassen inneholder konstanter for koordinatene i basistrekantens hjørner. Panelets paintComponent-metode foretar kall på den rekursive tegnemetoden for hver av basistrekantens sider, og med den orden som er satt. For ordenen er det set- og get-metoder. Java-fil for klassen kan lastes ned ved å klikke på linken KochPanel.java

 1 import java.awt.*;
 2 import javax.swing.*;
 3
 4 public class KochPanel extends JPanel
 5 {
 6   private final int BREDDE = 600;
 7   private final int HØYDE = 600;
 8   private double SQ = Math.sqrt(3.0) / 6; //brukes i koordinatberegning
 9   private final int TOPPX = 300, TOPPY = 20;//koordinater for hjørner i
10   private final int VENSTREX = 23, VENSTREY = 500; //likesidet trekant, 
11   private final int HØYREX = 577, HØYREY = 500; //dvs. kurve av orden 1
12   private int ønsketOrden; //orden for kurve som skal tegnes (1,2, ...)
13
14   public KochPanel(int startorden)
15   {
16     ønsketOrden = startorden;
17     setBackground(Color.black);
18     setPreferredSize(new Dimension(BREDDE, HØYDE));
19   }
20
21   public void tegnFraktal(int orden, int x1, int y1, int x5, int y5,
22           Graphics g)
23   {
       < som ovenfor >
44   }
45
46   public void paintComponent(Graphics g)
47   {
48     super.paintComponent(g);
49     g.setColor(Color.green);
50     tegnFraktal(ønsketOrden, TOPPX, TOPPY, VENSTREX, VENSTREY, g);
51     tegnFraktal(ønsketOrden, VENSTREX, VENSTREY, HØYREX, HØYREY, g);
52     tegnFraktal(ønsketOrden, HØYREX, HØYREY, TOPPX, TOPPY, g);
53   }
54
55   public void setOrden(int orden)
56   {
57     ønsketOrden = orden;
58   }
59
60   public int getOrden()
61   {
62     return ønsketOrden;
63   }
64 }

Appletklasse som bruker tegnepanelet er gjengitt nedenfor. Du kan laste den ned fra linken KochSnowflake.java. Klassen inneholder funksjonalitet for brukeren til å velge med hvilken orden kurva skal tegnes. På grunn av begrenset oppløsning på skjermen, er det ingen vits i å tegne kurver av høyere orden enn 9. Du kan kjøre appleten ved å klikke på linken KochApplet.

 1 import java.awt.*;
 2 import java.awt.event.*;
 3 import javax.swing.*;
 4
 5 public class KochSnowflake extends JApplet implements ActionListener
 6 {
 7   private final int APPLETBREDDE = 700, APPLETHØYDE = 700;
 8   private final int MIN = 1, MAX = 9;
 9   private JButton øk, mink;
10   private JLabel orden;
11   private KochPanel tegning;
12
13   public void init()
14   {
15     øk = new JButton("Tegn med høyere orden");
16     mink = new JButton("Tegn med lavere orden");
17     øk.addActionListener(this);
18     mink.addActionListener(this);
19     JPanel nordp = new JPanel();
20     nordp.add(new JLabel("Koch's snøflakkurve"));
21     nordp.add(mink);
22     nordp.add(øk);
23     orden = new JLabel("Orden: 1");
24     nordp.add(orden);
25     tegning = new KochPanel(MIN);
26     Container c = getContentPane();
27     c.add(nordp, "North");
28     c.add(tegning, "Center");
29     setSize(APPLETBREDDE, APPLETHØYDE);
30   }
31
32   public void actionPerformed(ActionEvent e)
33   {
34     int kurveorden = tegning.getOrden();
35     if (e.getSource() == øk)
36     {
37       kurveorden++;
38     }
39     else
40     {
41       kurveorden--;
42     }
43
44     if (kurveorden >= MIN && kurveorden <= MAX)
45     {
46       orden.setText("Orden: " + kurveorden);
47       tegning.setOrden(kurveorden);
48       repaint();
49     }
50   }
51 }

Følgende bilde viser en kurve av orden 5.

Innholdsoversikt for programutvikling

Copyright © Kjetil Grønning og Eva Hadler Vihovde, revidert 2012