



<html>
<head>
  <title>javabog.dk -  - Komponentbaseret programmering</title>
  <link rev="stylesheet" type="text/css" href="../typografi.css">
  <meta name="description" content="Lærebog i Java. Af Jacob Nordfalk. Udkommet hos Forlaget Globe">
  <meta name="keywords" content="designmønster, programmering, OOP, objekter, klasser, objektorienteret programmering, Java, JSP, lærebog, UML, IT">
</head>
<body bgcolor="#ffffff">



<a href='http://javabog.dk/'>javabog.dk</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='kapitel3.jsp'>&lt;&lt; forrige</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='indhold.jsp'>indhold</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='kapitel5.jsp'>n&aelig;ste &gt;&gt;</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='kode/'>programeksempler</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='../index_VP.html'>om bogen</a>

<H1 CLASS="western" STYLE="">4 <a name='afsn4'></a>Komponentbaseret
programmering</H1>
<DIV ID="Indholdsfortegnelse8">
  <P STYLE="margin-top: 0.3cm; margin-bottom: 0cm"><BR>
  </P>
  <P STYLE="margin-left: 0.3cm; margin-top: 0.15cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 11pt"><B>4.1
  Genbrugelige komponenter  64</B></FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">4.1.1
  Javab&oslash;nner  64</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">4.1.2
  Eksempel: B&oslash;nnen TextField  64</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">4.1.3
  Bruge en javab&oslash;nne  65</FONT></FONT></P>
  <P STYLE="margin-left: 0.3cm; margin-top: 0.15cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 11pt"><B>4.2
  At definere javab&oslash;nner  67</B></FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">4.2.1
  En meget simpel b&oslash;nne: GentagTekst  67</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">4.2.2
  Brug af b&oslash;nner fra et udviklingsv&aelig;rkt&oslash;j  68</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">4.2.3
  St&oslash;rrelsen af en grafisk komponent  68</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">4.2.4
  Skelne mellem udviklings- og i k&oslash;rselsfasen  69</FONT></FONT></P>
  <P STYLE="margin-left: 0.3cm; margin-top: 0.15cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 11pt"><B>4.3
  Karakteristika ved javab&oslash;nner  70</B></FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">4.3.1
  B&oslash;nner skal have en parameterl&oslash;s konstrukt&oslash;r  70</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">4.3.2
  B&oslash;nner kan have egenskaber  70</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">4.3.3
  B&oslash;nner kan have tilknyttet ekstra information  71</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">4.3.4
  B&oslash;nner b&oslash;r v&aelig;re afgr&aelig;nsede og
  uafh&aelig;ngige  71</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">4.3.5
  B&oslash;nner kan underst&oslash;tte h&aelig;ndelses-lyttere  71</FONT></FONT></P>
  <P STYLE="margin-left: 0.3cm; margin-top: 0.15cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 11pt"><B>4.4
  Ekstra eksempler  73</B></FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">4.4.1
  Rystetekst  73</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">4.4.2
  Rulletekst  74</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">4.4.3
  Simpel kryptering  75</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">4.4.4
  Eksempel p&aring; brug af b&oslash;nnerne i et v&aelig;rkt&oslash;j  76</FONT></FONT></P>
  <P STYLE="margin-left: 0.3cm; margin-top: 0.15cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 11pt"><B>4.5
  Opgaver  78</B></FONT></FONT></P>
  <P STYLE="margin-left: 0.3cm; margin-top: 0.15cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 11pt"><B>4.6
  L&oslash;sninger  79</B></FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">4.6.1
  Grafisk komponent: GentagTekst  79</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">4.6.2
  Grafisk komponent: Billede  79</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">4.6.3
  Webserver-komponent  80</FONT></FONT></P>
  <P STYLE="margin-left: 0.3cm; margin-top: 0.15cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 11pt"><B>4.7
  Avanceret  81</B></FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">4.7.1
  En komponent til at tegne kurver  81</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">4.7.2
  Repr&aelig;sentation af funktioner  84</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">4.7.3
  Fortolkning af strenge til funktioner  86</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">4.7.4
  Layout-manageres virkem&aring;de  87</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">4.7.5
  &Oslash;velse: Samspil med layout-manager  88</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">4.7.6
  Opgave: Adresseindtastningskomponent  88</FONT></FONT></P>
  <P STYLE="margin-left: 0.6cm; margin-top: 0.08cm; margin-bottom: 0cm">
  <FONT FACE="Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">4.7.7
  L&oslash;sning: Adresseindtastningskomponent  89</FONT></FONT></P>
</DIV>

<P CLASS="kapiteloversigt-western">Eksemplet i <a href='kapitel4.jsp#afsn4.7.3'>afsnit 4.7.3</a>
foruds&aelig;tter <a href='kapitel3.jsp'>kapitel 3</a>, Rekursion.</P>
<H2 CLASS="western">4.1 <a name='afsn4.1'></a>Genbrugelige komponenter</SPAN></H2>
<P CLASS="western">Komponenter er programm&oslash;rens byggeklodser:
De kan bruges igen og igen i mange sammenh&aelig;nge og s&aelig;ttes
sammen p&aring; alle mulige m&aring;der.</P>
<P CLASS="western">En bred definition p&aring; 'komponent' kunne v&aelig;re
'afgr&aelig;nset programdel, der kan genanvendes i flere
sammenh&aelig;nge'. Med denne definition er der dog ret meget, der er
komponenter:</P>
<UL>
  <LI><P CLASS="western">Grafiske komponenter: Button, Label,
  TextField, Checkbox, ...</P>
  <LI><P CLASS="western">Ikke-grafiske komponenter: <SPAN LANG="da-DK">CheckboxGroup</SPAN>,
  en FTP-komponent, ...</P>
  <LI><P CLASS="western"><SPAN LANG="da-DK">Appletter</SPAN>,
  <SPAN LANG="da-DK">servletter</SPAN>, Enterprise JavaBeans (EJB),
  ...</P>
  <LI><P CLASS="western">De fleste klasser kan bruges igen og igen,
  f.eks. String, Date, ...</P>
</UL>
<P CLASS="western">For alle komponenter g&aelig;lder, at deres
omgivelser - beholderen eller containeren - ogs&aring; er vigtig. En
komponent skal bruges p&aring; en bestemt m&aring;de, og den vil ikke
fungere uden de rette omgivelser. F.eks. virker et TextField-objekt
ikke, hvis dets paint()-metode ikke kaldes (det s&oslash;rger
<SPAN LANG="da-DK">java.awt.Container</SPAN> for). En applet skal
indl&aelig;ses i en netl&aelig;ser/browser, en <SPAN LANG="da-DK">servlet</SPAN>
skal udf&oslash;res i en webserver. Et Date-objekt skal have kaldt de
rette metoder, osv.</P>
<H3 CLASS="western">4.1.1 <a name='afsn4.1.1'></a>Javab&oslash;nner</H3>
<P CLASS="western">En mere sn&aelig;ver definition af begrebet
komponent er: 'en afgr&aelig;nset programdel, der kan genanvendes i
flere sammenh&aelig;nge, som kan bruges i et udviklingsv&aelig;rkt&oslash;js
palette og som tillader brugeren at manipulere med dets egenskaber
ved hj&aelig;lp af v&aelig;rkt&oslash;jet'.</P>
<P CLASS="western">Denne definition peger hen p&aring; Javab&oslash;nner
(eng.: JavaBeans) som f.eks. de grafiske komponenter Button, Label,
TextField, Checkbox, ...</P>
<P CLASS="western">Javab&oslash;nner har en standardiseret m&aring;de
at unders&oslash;ge, hvilke egenskaber (eng.: properties) de har (med
get- og set-metoder, se senere), og de fleste udviklingsv&aelig;rkt&oslash;jer
ved derfor, hvordan disse komponenter kan konfigureres.</P>
<P CLASS="western">Der er derfor ingen kode i v&aelig;rkt&oslash;jet
beregnet specielt mod de enkelte javab&oslash;nner. Nye b&oslash;nner
kan uden videre f&oslash;jes til udviklingsv&aelig;rkt&oslash;jets
palette. Senere i kapitlet vil vi selv programmere nogle b&oslash;nner
og f&oslash;je dem til paletten. 
</P>
<H3 CLASS="western">4.1.2 <a name='afsn4.1.2'></a><IMG SRC="bog5_html_m29d515ac.png" NAME="Grafik20" ALIGN=RIGHT BORDER=0>Eksempel:
B&oslash;nnen TextField</H3>
<P CLASS="western">Eksempelvis har TextField nogle egenskaber:</P>
<P CLASS="western"><I>text</I> angiver, hvad der st&aring;r i feltet.</P>
<P CLASS="western"><I>columns</I> angiver, hvor bredt feltet skal
v&aelig;re.</P>
<P CLASS="western"><I>editable</I> angiver, om brugeren kan redigere
teksten i <SPAN LANG="da-DK">indtastningsfeltet.</SPAN></P>
<P CLASS="western"><I><SPAN LANG="da-DK">echoChar</SPAN></I> bruges
til felter, der skal skjule det indtastede, typisk adgangskoder. 
</P>

<TABLE BORDER=0 CELLPADDING=0 CELLSPACING=0>
  <COL*>
  <COL*>
  <COL*>
  <COL*>
  <THEAD>
    <TR VALIGN=TOP>
      <TH>
        <P CLASS="western">Egenskab</P>
      </TH>
      <TH>
        <P CLASS="western">Type</P>
      </TH>
      <TH>
        <P CLASS="western">S&aelig;ttes med metoden</P>
      </TH>
      <TH>
        <P CLASS="western">Afl&aelig;ses med metoden</P>
      </TH>
    </TR>
  </THEAD>
  <TBODY>
    <TR VALIGN=TOP>
      <TD>
        <P CLASS="western">text</P>
      </TD>
      <TD>
        <P CLASS="western">String</P>
      </TD>
      <TD>
        <P CLASS="western"><SPAN LANG="da-DK">setText</SPAN>(String t)</P>
      </TD>
      <TD>
        <P CLASS="western"><SPAN LANG="da-DK">getText</SPAN>()</P>
      </TD>
    </TR>
    <TR VALIGN=TOP>
      <TD>
        <P CLASS="western">editable</P>
      </TD>
      <TD>
        <P CLASS="western">boolean</P>
      </TD>
      <TD>
        <P CLASS="western"><SPAN LANG="da-DK">setEditable</SPAN>(boolean
        rediger)</P>
      </TD>
      <TD>
        <P CLASS="western"><SPAN LANG="da-DK">isEditable</SPAN>()</P>
      </TD>
    </TR>
    <TR VALIGN=TOP>
      <TD>
        <P CLASS="western">columns</P>
      </TD>
      <TD>
        <P CLASS="western">int</P>
      </TD>
      <TD>
        <P CLASS="western"><SPAN LANG="da-DK">setColumns</SPAN>(int
        bredde)</P>
      </TD>
      <TD>
        <P CLASS="western"><SPAN LANG="da-DK">getColumns</SPAN>()</P>
      </TD>
    </TR>
    <TR VALIGN=TOP>
      <TD>
        <P CLASS="western">echoChar</P>
      </TD>
      <TD>
        <P CLASS="western">char</P>
      </TD>
      <TD>
        <P CLASS="western"><SPAN LANG="da-DK">setEchoChar</SPAN>(char
        tegn)</P>
      </TD>
      <TD>
        <P CLASS="western"><SPAN LANG="da-DK">getEchoChar</SPAN>()</P>
      </TD>
    </TR>
  </TBODY>
</TABLE>
<H4 CLASS="western">Abonnement p&aring; h&aelig;ndelser</H4>
<P CLASS="western">B&oslash;nnen kan blandt andet sende
Action-h&aelig;ndelser. Det betyder at, den har metoderne</P>
<PRE CLASS="kode-western">  public void <SPAN LANG="da-DK">addActionListener</SPAN>(<SPAN LANG="da-DK">ActionListener</SPAN> l)
  public void <SPAN LANG="da-DK">removeActionListener</SPAN>(ActionListener l)</PRE><P CLASS="western">
til at tilf&oslash;je og fjerne en lytter p&aring; denne komponent. 
</P>
<P CLASS="western">Trykker man retur i indtastningsfeltet, oprettes
et h&aelig;ndelses-objekt (af type <SPAN LANG="da-DK">ActionEvent</SPAN>),
og alle lytterne f&aring;r kaldt metoden <SPAN LANG="da-DK">actionPerformed</SPAN>()
med dette objekt.</P>
<H3 CLASS="western">4.1.3 <a name='afsn4.1.3'></a>Bruge en javab&oslash;nne</H3>
<P CLASS="western">Lad os lave et program, der bruger b&oslash;nnen
TextField, s&aelig;tter b&oslash;nnens egenskab <I>text,</I> lytter
efter, om brugeren trykker retur i indtastningsfeltet (abonnerer p&aring;
Action-h&aelig;ndelser fra komponenten) og udskriver indholdet af
tekstfeltet, n&aring;r det sker. 
</P>
<H4 CLASS="western">Bruge en javab&oslash;nne fra et
udviklingsv&aelig;rkt&oslash;j</H4>
<P CLASS="western">Genereres koden med et udviklingsv&aelig;rkt&oslash;j,
kommer kildeteksten til at se nogenlunde s&aring;ledes ud:</P>
<PRE CLASS="kode-western">import java.awt.*;
import java.awt.event.*;

public class <SPAN LANG="da-DK">BenytBoenneMedVaerktoej</SPAN> extends Frame
{
  <B>TextField <SPAN LANG="da-DK">textFieldNavn</SPAN> = new TextField()</B>;      <I>// opret b&oslash;nnen</I>

  public BenytBoenneMedVaerktoej() {
    try {
      <SPAN LANG="da-DK">jbInit</SPAN>();
    }
    catch(Exception e) {
      <SPAN LANG="da-DK">e.printStackTrace</SPAN>();
    }
  }

  private void jbInit() throws Exception {
    <B><SPAN LANG="da-DK">textFieldNavn.setText</SPAN>(&quot;Jacob&quot;)</B>;               <I>// s&aelig;t egenskaben text</I>

<I>    // anonym indre klasse lytter p&aring; h&aelig;ndelser og kalder derp&aring; videre til</I>
<I>    // metoden textFieldNavn_actionPerformed()</I>
<B>    <SPAN LANG="da-DK">textFieldNavn.addActionListener</SPAN></B>(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        textFieldNavn_actionPerformed(e);
      }
    });

    <SPAN LANG="da-DK">textFieldNavn.setBounds</SPAN>(new Rectangle(141, 61, 112, 29));
    <SPAN LANG="da-DK">this.setLayout</SPAN>(null);
    <SPAN LANG="da-DK">this.add</SPAN>(textFieldNavn, null);
  }

  void textFieldNavn_actionPerformed(ActionEvent e) {
    String navn = <SPAN LANG="da-DK">textFieldNavn.getText</SPAN>();        <I>// afl&aelig;s egenskaben text</I>
    System.out.println(&quot;Navnet er: &quot;+navn);
  }

  public static void main(String[] arg)
  {
    <SPAN LANG="da-DK">BenytBoenneMedVaerktoej</SPAN> vindue = new BenytBoenneMedVaerktoej();
    <SPAN LANG="da-DK">vindue.setSize</SPAN>(350,100);                      <I>// s&aelig;t vinduets st&oslash;rrelse</I>
    <SPAN LANG="da-DK">vindue.setVisible</SPAN>(true);                      <I>// &aring;bn vinduet</I>
  }
}</PRE><P CLASS="western">
Der er oprettet en konstrukt&oslash;r, der kalder metoden jbInit().
Et udviklingsv&aelig;rkt&oslash;j definerer gerne en separat metode,
hvor den initialiserer komponenterne. I JBuilder og <SPAN LANG="da-DK">JDeveloper</SPAN>
hedder den jbInit(), mens den hedder <SPAN LANG="da-DK">initComponents</SPAN>()
i <SPAN LANG="da-DK">Netbeans</SPAN> og Sun ONE Studio.</P>
<P CLASS="western">I metoden jbInit() l&aelig;gger v&aelig;rkt&oslash;jet
koden til at initialisere de grafiske komponenter og s&oslash;rger
for at placere dem korrekt i vinduet. F&oslash;jer du din egen kode
til denne metode, s&aring; s&oslash;rg for, at det ligner v&aelig;rkt&oslash;jets
egen kode, ellers kan v&aelig;rkt&oslash;jet have sv&aelig;rt ved at
opretholde sammenh&aelig;ngen mellem kode og design.</P>

<P CLASS="western" STYLE="">Der er brugt en
anonym indre klasse<A CLASS="sdfootnoteanc" NAME="sdfootnote1anc" HREF="#sdfootnote1sym"><SUP>1</SUP></A>
til at lytte p&aring; h&aelig;ndelser (defineret i parameteren til
textFieldNavn.addActionListener()). N&aring;r h&aelig;ndelsen sker,
kalder lytter-objektet videre i metoden
textFieldNavn_actionPerformed(). 
</P>
<P CLASS="western">I princippet kunne der alts&aring; lige s&aring;
godt have <SPAN LANG="da-DK">st&aring;et</SPAN>:</P>
<PRE CLASS="kode-western">    textFieldNavn.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        String navn = textFieldNavn.getText();
        System.out.println(&quot;Navnet er: &quot;+navn);
      }
    });</PRE><H4 CLASS="western">
Bruge en javab&oslash;nne uden et udviklingsv&aelig;rkt&oslash;j</H4>
<P CLASS="western">Skriver man koden selv uden hj&aelig;lp fra et
udviklingsv&aelig;rkt&oslash;j, vil man sandsynligvis l&aelig;gge
initialiseringen direkte i konstrukt&oslash;ren og lade klassen selv
v&aelig;re en ActionListener i stedet for at definere en indre
klasse. S&aring; kommer kildeteksten til at se nogenlunde s&aring;ledes
ud:</P>
<PRE CLASS="kode-western">import java.awt.*;
import java.awt.event.*;

public class <SPAN LANG="da-DK">BenytBoenneSkrevetSelv</SPAN> extends Frame <B>implements ActionListener</B>
{
  TextField textFieldNavn = new TextField();

  public BenytBoenneSkrevetSelv() {
    textFieldNavn.setText(&quot;Jacob&quot;);

<I>    // klassen selv lytter p&aring; h&aelig;ndelser</I>
<B>    textFieldNavn.addActionListener(this)</B>;

    textFieldNavn.setBounds(new Rectangle(141, 61, 112, 29));
    this.setLayout(null);
    this.add(textFieldNavn, null);
  }

  public void actionPerformed(ActionEvent e) {
    String navn = textFieldNavn.getText();
    System.out.println(&quot;Navnet er: &quot;+navn);
  }

  public static void main(String[] arg) {
    BenytBoenneSkrevetSelv vindue = new BenytBoenneSkrevetSelv();
    vindue.setSize(350,100);
    vindue.setVisible(true);              
  }
}</PRE><P CLASS="western">
Vi har ladet vinduet selv implementere ActionListener, hvorfor vi
blot skriver</P>
<PRE CLASS="kode-western">    textFieldNavn.addActionListener(this);</PRE><P CLASS="western">
og definerer actionPerformed() selv.</P>
<H2 CLASS="western" STYLE="">4.2 <a name='afsn4.2'></a>At definere
javab&oslash;nner</SPAN></H2>
<P CLASS="western" STYLE="font-style: normal">Lad os nu se p&aring;,
hvordan vi selv definerer komponenter/javab&oslash;nner.</P>
<P CLASS="western">N&aring;r man definerer sine egne javab&oslash;nner,
skal man holde tungen lige i munden og huske at skelne mellem tre
roller:</P>
<UL>
  <LI><P CLASS="western"><B>Programm&oslash;ren af b&oslash;nnen
  (leverand&oslash;ren)</B> er den person, der skriver b&oslash;nnens
  kode (dvs. koden <I>inde i </I>klassen), men kan ikke antage s&aring;
  meget om, hvordan b&oslash;nnen vil blive brugt. En b&oslash;nne
  skal kunne benyttes helt uden at kende den kode, som leverand&oslash;ren
  af b&oslash;nnen har lavet, og v&aelig;re tilpas generel og
  genanvendelig til, at en anden programm&oslash;r kan bruge den.
  Eksempelvis skulle leverand&oslash;ren til TextField (en programm&oslash;r
  ansat i Sun) kode den, s&aring; den ikke afh&aelig;nger ret meget af
  sine omgivelser.</P>
  <LI><P CLASS="western"><B>Programm&oslash;ren, der anvender b&oslash;nnen
  i sit program (klienten)</B>. I denne rolle (som er den mest
  almindelige) g&oslash;r man brug af en b&oslash;nne (klasse), som en
  anden programm&oslash;r har skrevet (dvs. man skriver kode <I>uden
  for</I> klassen). Eksempel: At bruge TextField udefra, f.eks. ved i
  et udviklingsv&aelig;rkt&oslash;j at f&oslash;je den til den
  grafiske brugergr&aelig;nseflade.</P>
  <LI><P CLASS="western"><SPAN STYLE="font-style: normal"><B>Slutbrugeren
  af programmet</B><SPAN STYLE="font-weight: medium"> beh&oslash;ver
  ikke, kende noget til, hvordan koden til hverken b&oslash;nnen eller
  for den sags skyld resten af programmet ser ud.</SPAN></SPAN></P>
</UL>
<H3 CLASS="western">4.2.1 <a name='afsn4.2.1'></a>En meget simpel b&oslash;nne: GentagTekst</H3>
<P CLASS="western">Herunder er en simpel grafisk b&oslash;nne, der
tegner en tekst tre gange skr&aring;t under hinanden.</P>
<PRE CLASS="kode-western">package vp;
import java.awt.*;
public class GentagTekst extends Component
{
  private String <SPAN LANG="da-DK">tekstDerSkalVises</SPAN> = &quot;gentag&quot;;

  <B>public void <SPAN LANG="da-DK">setTekst</SPAN>(String t) </B>
  {
    tekstDerSkalVises = t;
  }

  <B>public String <SPAN LANG="da-DK">getTekst</SPAN>()</B>
  {
    return tekstDerSkalVises;
  }

  public void paint(Graphics g)
  {
    <SPAN LANG="da-DK">g.drawString</SPAN>(tekstDerSkalVises, 0, 10);
    g.drawString(tekstDerSkalVises, 5, 15);
    g.drawString(tekstDerSkalVises, 10,20);
  }
}</PRE><P CLASS="western">
Ud fra kildeteksten ses, at b&oslash;nnen har egenskaben <I>tekst</I>
(der bestemmer, hvilken tekst der skal vises).</P>
<BLOCKQUOTE CLASS="definition-western">En javab&oslash;nne siges at
have en egenskab, hvis den har en tilsvarende get- og/eller
set-metode</BLOCKQUOTE>
<P CLASS="western">Bem&aelig;rk at en <SPAN LANG="da-DK">javab&oslash;nnes</SPAN>
egenskaber ikke har nogen given relation til de objektvariabler, den
m&aring;tte have. S&aring;ledes har b&oslash;nnen egenskaben <I>tekst</I>,
fordi den har metoden getTekst() og/eller setTekst(), og hvordan
b&oslash;nnen husker egenskaben internt (her sker det i den private
variabel tekstDerSkalVises) er sagen uvedkommende, set udefra.</P>
<P CLASS="western">Visse udviklingsv&aelig;rkt&oslash;jer - herunder
JBuilder - kan kun h&aring;ndtere b&oslash;nner, der ligger i en
pakke, s&aring; derfor er alle eksemplerne lagt i pakken 'vp' (husk,
at de s&aring; ogs&aring; ligger i undermappen 'vp' i forhold til en
<SPAN LANG="da-DK">kildetekstfil</SPAN>, der ikke l&aring; i en
pakke).</P>
<H3 CLASS="western" STYLE="font-style: normal">4.2.2 <a name='afsn4.2.2'></a>Brug af b&oslash;nner
fra et udviklingsv&aelig;rkt&oslash;j</H3>
<P CLASS="western">S&aring; snart b&oslash;nnen er oversat er den
klar til brug og kan bruges fra udviklingsv&aelig;rkt&oslash;jet.</P>
<P CLASS="western">I <SPAN STYLE="font-style: normal">JBuilder kan
det g&oslash;res ved at klikke p&aring; den lille kasse til venstre
for komponenterne p&aring; design-fanen og v&aelig;lge b&oslash;nnen
direkte.</SPAN></P>
<P CLASS="western" STYLE="font-style: normal">Ellers skal du f&oslash;rst
definere et bibliotek, der indeholder b&oslash;nnen:</P>
<UL>
  <LI><P CLASS="western" STYLE="font-style: normal">I JBuilder: v&aelig;lg
  'Tools | Configure Libraries', v&aelig;lg '<SPAN LANG="da-DK">New..</SPAN>'
  og 'Add...', og angiv stien (roden) til .class-filerne. 
  </P>
  <LI><P CLASS="western">I JDeveloper: v&aelig;lg 'Project | Default
  project settings', under 'Libraries' v&aelig;lg 'New...' og angiv
  stien (roden) til .class-filerne.</P>
</UL>
<P CLASS="western">Nu kan du konfigurere paletten med 'Tools |
Configure palette', v&aelig;lg 'Add component', og v&aelig;lg den
fane, du &oslash;nsker komponenten skal vises p&aring; (f.eks.
'AWT'). 
</P>
<P CLASS="western">Under 'Library' v&aelig;lger du det bibliotek du
lige har oprettet og derp&aring; klassen i det.</P>
<H4 CLASS="western">Kode genereret af udviklingsv&aelig;rkt&oslash;jet</H4>
<P CLASS="western"><SPAN STYLE="font-style: normal">Ud</SPAN>viklingsv&aelig;rkt&oslash;jet
kan nu generere et program, der bruger b&oslash;nnen. 
</P>
<P CLASS="western">V&aelig;lger man b&oslash;nnens egenskaber, vil
man se, at den har egenskaben <I>tekst</I><SPAN STYLE="font-style: normal">,
ud over</SPAN> de, der er arvet fra Component (f.eks. forgrunds- og
baggrundsfarve). 
</P>
<P CLASS="western">Den genererede kode ser s&aring;ledes ud (for
JBuilder og JDeveloper):</P>
<PRE CLASS="kode-western">import vp.*;
import java.awt.*;

public class <SPAN LANG="da-DK">VindueMedGentagTekst</SPAN> extends Frame
{
<B>  GentagTekst gentagtekst1 = new GentagTekst();</B>

  public VindueMedGentagTekst() {
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }

  private void jbInit() throws Exception  {
    <SPAN LANG="da-DK">this.setSize</SPAN>(new Dimension(319, 247));
    this.setLayout(null);

<B>    gentagtekst1.setTekst(&quot;ryst!&quot;);</B>
    gentagtekst1.setBounds(new Rectangle(177, 190, 111, 28));
    this.add(gentagtekst1, null);
  }
}</PRE><H3 CLASS="western">
4.2.3 <a name='afsn4.2.3'></a>St&oslash;rrelsen af en grafisk komponent</H3>
<P CLASS="western">Pr&oslash;ver man at bruge GentagTekst som en
b&oslash;nne, opdager man at den som udgangspunkt bliver meget lille
(den f&aring;r en bredde og h&oslash;jde p&aring; nul). Det h&aelig;nger
sammen med, at alle grafiske komponenter skal kunne fort&aelig;lle
deres omgivelser, hvor store de har behov for at v&aelig;re p&aring;
sk&aelig;rmen for at kunne fungere korrekt.</P>
<P CLASS="western">Det sker ved, at omgivelserne kalder metoden
<SPAN LANG="da-DK">getPreferredSize</SPAN>(), der skal returnere et
Dimension-objekt med den foretrukne bredde og h&oslash;jde. 
</P>
<P CLASS="western">Herunder er endnu en grafisk komponent. Fordi vi
har defineret getPreferredSize(), vil udviklingsv&aelig;rkt&oslash;j
og layout-managere s&aring; vidt muligt rette sig efter denne
st&oslash;rrelse.</P>
<P CLASS="western">Layout-managere og deres virkem&aring;de er
beskrevet mere grundigt i <a href='kapitel4.jsp#afsn4.7.4'>afsnit 4.7.4</a>.</P>
<PRE CLASS="kode-western">package vp;
import java.awt.*;
public class <SPAN LANG="da-DK">BoenneMedForetrukkenStr</SPAN> extends Component
{
  Dimension <SPAN LANG="da-DK">foretrukneSt&oslash;rrelse</SPAN> = new Dimension(100,50);

  <I>/** fort&aelig;l containeren hvad denne komponents foretrukne st&oslash;rrelse er */</I>
<B>  public Dimension getPreferredSize()</B>
<B>  {</B>
<B>    return foretrukneSt&oslash;rrelse;</B>
<B>  }</B>

  public void paint(Graphics g)
  {
    Dimension str = <SPAN LANG="da-DK">getSize</SPAN>();  <I>// faktisk st&oslash;rrelse (kan variere fra foretrukne)</I>
    <SPAN LANG="da-DK">g.drawOval</SPAN>(0, 0, <SPAN LANG="da-DK">str.width</SPAN>, <SPAN LANG="da-DK">str.height</SPAN>);
  }
}</PRE><P CLASS="western">
Ud over getPreferredSize() findes ogs&aring; <SPAN LANG="da-DK">getMinimumSize</SPAN>()
og <SPAN LANG="da-DK">getMaximumSize</SPAN>():</P>
<PRE CLASS="kode-western">  public Dimension getMinimumSize()
  public Dimension getMaximumSize()</PRE><P CLASS="western">
Disse bruges (sammen med getPreferredSize()) af containerens
layout-manager for at afg&oslash;re, hvordan containerens komponenter
skal placeres indbyrdes. Det er alts&aring;, ligesom med
pant()-metoden, ikke meningen, at man selv kalder dem, men at
systemet (containerens layout-manager) kalder dem, n&aring;r der er
brug for det (f.eks. n&aring;r vinduet &aelig;ndrer st&oslash;rrelse).</P>
<H3 CLASS="western">4.2.4 <a name='afsn4.2.4'></a>Skelne mellem udviklings- og i k&oslash;rselsfasen</H3>
<P CLASS="western">N&aring;r man i udviklingsfasen bruger
<SPAN LANG="da-DK">designv&aelig;rkt&oslash;jet</SPAN> til at designe
sk&aelig;rmbilleder og l&aelig;gger en komponent (b&oslash;nne) ind
p&aring; sk&aelig;rmbilledet, sker der det, at v&aelig;rkt&oslash;jet
rent faktisk opretter b&oslash;nnen (med new), s&aelig;tter dens
egenskaber tilsvarende (med kald af set-metoder) og viser b&oslash;nnen
p&aring; sk&aelig;rmen.</P>
<P CLASS="western">Nogle gange har en b&oslash;nne imidlertid brug
for at vide, om den lige nu er i gang med at blive brugt af et
udviklingsv&aelig;rkt&oslash;j under udviklingsfasen eller om den
rent faktisk er en del af et k&oslash;rende program. Det kunne f.eks.
v&aelig;re relevant, hvis b&oslash;nnen lagde beslag p&aring; nogle
vigtige resurser eller hvis den havde et h&oslash;jt processor- eller
hukommelsesforbrug.</P>
<P CLASS="western">En b&oslash;nne kan unders&oslash;ge, om den er i
udviklingsfasen/<SPAN LANG="da-DK">designfasen</SPAN> (og alts&aring;
k&oslash;rer i et udviklingsv&aelig;rkt&oslash;j) eller i
k&oslash;rselsfasen ved at kalde metoden
<SPAN LANG="da-DK">java.beans.Beans.isDesignTime</SPAN>():</P>
<PRE CLASS="kode-western">package vp;
import java.awt.*;
public class <SPAN LANG="da-DK">BoenneGenkenderDesignfase</SPAN> extends Component
{
  Dimension foretrukneSt&oslash;rrelse = new Dimension(100,50);

  public Dimension getPreferredSize()
  {
    return foretrukneSt&oslash;rrelse;
  }

  public void paint(Graphics g)
  {
    <B>if (java.beans.Beans.isDesignTime())</B>
    {
      g.drawString(&quot;<SPAN LANG="da-DK">Designfase</SPAN>&quot;,5,15);
    } else {
      g.drawString(&quot;Under k&oslash;rsel&quot;,5,15);
    }
  }
}</PRE>
<H2 CLASS="western" STYLE="">4.3 <a name='afsn4.3'></a>Karakteristika
ved javab&oslash;nner</SPAN></H2>
<P CLASS="western">Der er visse karakteristika ved javab&oslash;nner,
som g&oslash;r det muligt at behandle dem som afgr&aelig;nsede
komponenter og konfigurere dem med et udviklingsv&aelig;rkt&oslash;j.
Disse er ridset op i det f&oslash;lgende.</P>
<H3 CLASS="western">4.3.1 <a name='afsn4.3.1'></a>B&oslash;nner skal have en parameterl&oslash;s
konstrukt&oslash;r</H3>
<P CLASS="western"><SPAN STYLE="font-style: normal">B&oslash;nner
</SPAN><I>skal</I><SPAN STYLE="font-style: normal"> have en
konstrukt&oslash;r uden parametre, dvs. de skal kunne oprettes som
f.eks.:</SPAN></P>
<PRE CLASS="kode-western">  GentagTekst gentagtekst1 = new GentagTekst();</PRE><P CLASS="western">
<SPAN STYLE="font-style: normal">D</SPAN>ette er, for at
udviklingsv&aelig;rkt&oslash;jet kan oprette komponenterne p&aring;
en ensartet m&aring;de. 
</P>
<P CLASS="western">Pr&oslash;v, for at illustrere n&oslash;dvendigheden
af dette krav, at forestille dig, at kravet <I>ikke</I> fandtes: S&aring;
skulle<SPAN LANG="da-DK"> udviklingsv&aelig;rkt&oslash;jet </SPAN>kunne
h&aring;ndtere klasser med meget indviklede konstrukt&oslash;rer,
f.eks. en med 17 parametre, hvor parameter nummer 6 i &oslash;vrigt
altid skal v&aelig;re st&oslash;rre end parameter 7 og parameter 16
v&aelig;re et lige tal st&oslash;rre end 38. Et menneske kunne
selvf&oslash;lgelig l&aelig;se dokumentationen og forst&aring;
kravene, mens det er helt umuligt for v&aelig;rkt&oslash;jet at
im&oslash;dekomme s&aring;danne krav.</P>
<P CLASS="western">I <SPAN STYLE="font-style: normal">stedet for at
angive startv&aelig;rdierne i konstrukt&oslash;ren s&aelig;ttes de
som egenskaber.</SPAN></P>
<H3 CLASS="western">4.3.2 <a name='afsn4.3.2'></a>B&oslash;nner kan have egenskaber</H3>
<P CLASS="western" STYLE="font-style: normal">Egenskaberne
l&aelig;ses/s&aelig;ttes med de kendte get- og set-metoder. 
</P>
<P CLASS="western" STYLE="font-style: normal">Disse kan v&aelig;re
simple som f.eks.:</P>
<PRE CLASS="kode-western" STYLE="font-weight: medium">  public void setTekst(String t)
  public String getTekst()</PRE><P CLASS="western">
<SPAN STYLE="font-style: normal">Egenskaberne b&oslash;r v&aelig;re
uafh&aelig;ngige, forst&aring;et p&aring; den m&aring;de at b&oslash;nnen
ikke</SPAN> kan antage at en bestemt egenskab bliver sat eller at
egenskaberne bliver sat i en bestemt r&aelig;kkef&oslash;lge.</P>
<P CLASS="western" STYLE="font-style: normal">Arver man fra en b&oslash;nne,
vil de arvede egenskaber indg&aring; p&aring; lige fod med de nye
egenskaber. 
</P>
<P CLASS="western"><SPAN STYLE="font-style: normal">B&oslash;nnens
egenskaber kan v&aelig;re af en vilk&aring;rlig type, men v&aelig;rkt&oslash;jer
underst&oslash;tter som regel kun egenskaber af de simple typer (int,
double, ...) og objekter af type String, Color, Point, Dimension </SPAN>og
et par stykker til.  &Oslash;nsker man, at brugeren kan redigere
egenskaber af andre typer m&aring; man selv programmere, hvordan det
skal ske (se n&aelig;ste afsnit).</P>
<H4 CLASS="western">Indekserede egenskaber</H4>
<P CLASS="western">Egenskaber kan ogs&aring; v&aelig;re indekserede
(dvs. i et array) som f.eks.:</P>
<PRE CLASS="kode-western">  public void setTekst(String t[])
  public String[] getTekst()</PRE><P CLASS="western">
Ofte vil der da ogs&aring; v&aelig;re mulighed for at arbejde med en
enkelt indgang, f.eks.:</P>
<PRE CLASS="kode-western">  public void setTekst(int indeks, String t)
  public String getTekst(int indeks)</PRE><H4 CLASS="western">
Bundne og begr&aelig;nsede egenskaber</H4>
<P CLASS="western">Nogen gange er det hensigtsm&aelig;ssigt, at andre
kan f&aring; at vide, n&aring;r en egenskab bliver &aelig;ndret. Til
det form&aring;l <SPAN STYLE="font-style: normal">kan egenskaber v&aelig;re
bundne (eng.: bound) eller begr&aelig;nsede (eng.: constrained).</SPAN></P>
<P CLASS="western"><SPAN STYLE="font-style: normal">N&aring;r </SPAN><I>bundne
egenskaber</I><SPAN STYLE="font-style: normal"> &aelig;ndres,
afstedkommer det en h&aelig;ndelse (af typen <SPAN LANG="da-DK">PropertyChangeEvent</SPAN>).
Disse h&aelig;ndelser kan man lytte efter (ved at kalde
<SPAN LANG="da-DK">addPropertyChangeListener</SPAN>() p&aring;
komponenten med en lytter af typen <SPAN LANG="da-DK">PropertyChangeListener</SPAN>
som parameter). Man kan alts&aring; f&aring; at vide, n&aring;r en
bestemt egenskab &aelig;ndres, ved at &quot;abonnere&quot; p&aring;
den, og det foreg&aring;r p&aring; pr&aelig;cis samme m&aring;de som
med andre slags h&aelig;ndelser. </SPAN>
</P>
<P CLASS="western"><I>Begr&aelig;nsede egenskaber</I><SPAN STYLE="font-style: normal">
er som bundne egenskaber, men h&aelig;ndelserne, der sendes, er i
stedet af typen <SPAN LANG="da-DK">VetoableChangeEvent.</SPAN>
Lytterne (der er af typen <SPAN LANG="da-DK">VetoableChangeListener</SPAN>)
har lov til at kaste undtagelsen <SPAN LANG="da-DK">PropertyVetoException</SPAN>
for at annullere &aelig;ndringen af egenskaben.</SPAN></P>
<H3 CLASS="western">4.3.3 <a name='afsn4.3.3'></a>B&oslash;nner kan have tilknyttet ekstra
information</H3>
<P CLASS="western">Ekstra information om en b&oslash;nne ligger i en
s&aring;kaldt <SPAN LANG="da-DK">BeanInfo</SPAN>-klasse<A CLASS="sdfootnoteanc" NAME="sdfootnote2anc" HREF="#sdfootnote2sym"><SUP>2</SUP></A>.
F.eks. kunne <SPAN LANG="da-DK">GentagTekst.java</SPAN> have
tilknyttet klassen <SPAN LANG="da-DK">GentagTekstBeanInfo.java</SPAN>
til ekstra information.</P>
<P CLASS="western"><SPAN STYLE="font-style: normal">Denne information
er </SPAN><I>kun</I><SPAN STYLE="font-style: normal"> til hj&aelig;lp
for udviklingsv&aelig;rkt&oslash;jet. Hvis der ikke er en
BeanInfo-klasse, bruges introspektion (beskrevet i <a href='kapitel11.jsp'>kapitel 11</a>), dvs.
inspicering af b&oslash;nne-klassens metoder (egenskaber).
Introspektion er oftest tilstr&aelig;kkeligt, s&aring;
BeanInfo-klasser er ikke s&aring; almindelige. </SPAN>De ekstra
informationer, der kan specificeres i en BeanInfo-klasse, er:</P>
<UL>
  <LI><P CLASS="western">Hvilket ikon b&oslash;nnen skal repr&aelig;senteres
  af i v&aelig;rkt&oslash;jet</P>
  <LI><P CLASS="western">Hvilke egenskaber der findes, og for hver
  egenskab en beskrivelse og hvordan den afl&aelig;ses og s&aelig;ttes
    </P>
  <LI><P CLASS="western">Hvordan de redigeres. Der kan tilknyttes en
  klasse, der bestemmer f.eks.:</P>
</UL>
<UL>
  <LI><P CLASS="western" STYLE="margin-top: 0cm; margin-bottom: 0cm">Hvilke
  v&aelig;rdier der er mulige</P>
  <LI><P CLASS="western" STYLE="margin-top: 0cm; margin-bottom: 0cm">Hvilken
  javakode der skal s&aelig;ttes ind i kildeteksten</P>
  <LI><P CLASS="western" STYLE="margin-top: 0cm; margin-bottom: 0cm; font-style: normal">
  Om et skr&aelig;ddersyet <SPAN LANG="da-DK">redigeringsvindue</SPAN>
  skal dukke op</P>
</UL>
<H3 CLASS="western">4.3.4 <a name='afsn4.3.4'></a>B&oslash;nner b&oslash;r v&aelig;re
afgr&aelig;nsede og uafh&aelig;ngige</H3>
<P CLASS="western">Det siger sig selv, at en komponent, der skal
kunne bruges igen og igen i mange sammenh&aelig;nge, skal v&aelig;re
fuldst&aelig;ndig afgr&aelig;nset og uafh&aelig;ngig af omgivelserne.
Er den afh&aelig;ngig af dele af resten af programmet, kan den jo
netop ikke bruges uden disse programdele.</P>
<H3 CLASS="western">4.3.5 <a name='afsn4.3.5'></a>B&oslash;nner kan underst&oslash;tte
h&aelig;ndelses-lyttere</H3>
<P CLASS="western">Mange b&oslash;nner har brug for at fort&aelig;lle
resten af programmet (selvom b&oslash;nnen selvf&oslash;lgelig ikke
aner, hvilket program det m&aring;tte v&aelig;re), at der er sket
noget. 
</P>
<P CLASS="western">Det g&aring;r ikke, at b&oslash;nnen kalder en
metode i det omkringliggende program, for s&aring; ville b&oslash;nnen
ikke virke i andre sammenh&aelig;nge.</P>
<P CLASS="western">I stedet skal det omgivende program registrere et
lytter-objekt hos b&oslash;nnen, som b&oslash;nnen skal huske. N&aring;r
den f&aring;r brug for at fort&aelig;lle resten af programmet, at &quot;nu
er der er sket noget&quot; kalder den lytteren.</P>
<P CLASS="western">Det bedst kendte eksempel p&aring; dette er m&aring;ske
Button. For at f&aring; at vide, n&aring;r der trykkes p&aring; den,
skal vi registrere et ActionListener-objekt hos den. N&aring;r der
trykkes p&aring; knappen, vil den kalde metoden actionPerformed() p&aring;
lytteren med et ActionEvent-objekt som parameter, der beskriver
h&aelig;ndelsen.</P>
<P CLASS="western"><SPAN STYLE="font-style: normal">Hvis du nu skal
til at programmere din f&oslash;rste komponent nu, s&aring; bem&aelig;rk,
at du har skiftet rolle,<SPAN LANG="da-DK"> jvf. </SPAN><a href='kapitel4.jsp#afsn4.2'>afsnit 4.2</a>:
F&oslash;r har du kun </SPAN><I>anvendt</I><SPAN STYLE="font-style: normal">
andre komponenter og i den forbindelse derfor m&aring;ske </SPAN><I>kaldt</I><SPAN STYLE="font-style: normal">
f.eks. addActionListener()</SPAN>. 
</P>
<P CLASS="western">Nu laver du selv komponenter og skal derfor
<I>definere</I> <SPAN STYLE="font-style: normal">f.eks.
addActionListener(), hvis du vil have, at dine komponenter
underst&oslash;tter denne slags h&aelig;ndelser. Tilsvarende b&oslash;r
du definere en removeActionListener(), der fjerner en lytter fra din
komponent, s&aring; at sige &quot;annullerer abonnementet&quot; p&aring;
h&aelig;ndelserne.</SPAN> 
</P>
<P CLASS="western">Det vil ogs&aring; v&aelig;re en god id&eacute;
internt at huske, hvilke lyttere der er registreret, og definere en
intern metode, der kalder actionPerformed() p&aring; alle lytterne,
n&aring;r en h&aelig;ndelse skal affyres (man kunne passende kalde
metoden for <SPAN STYLE="font-weight: medium"><SPAN LANG="da-DK">sendActionPerformedTilLytterne</SPAN>()</SPAN>).</P>
<P CLASS="western">Herunder et eksempel p&aring; en komponent, der
sender Action-h&aelig;ndelser. De sendes, hver gang dets
paint()-metode kaldes (dette er ikke specielt hensigtsm&aelig;ssigt,
men giver et simpelt eksempel<A CLASS="sdfootnoteanc" NAME="sdfootnote3anc" HREF="#sdfootnote3sym"><SUP>3</SUP></A>).</P>
<PRE CLASS="kode-western">import <SPAN LANG="da-DK">java.awt.event.</SPAN>*;
import java.util.*;
import java.awt.*;

<I>/** En komponent, der sender en h&aelig;ndelse hver gang den gentegnes.</I>
<I> *  Du kan v&aelig;lge at kopiere kildeteksten ind i dit eget program.</I>
<I> *  H&aelig;ndelsen, der sendes er ActionEvent. Denne h&aelig;ndelse indeholder bl.a.:</I>
<I> *  &lt;ul&gt;</I>
<I> *  &lt;li&gt; et objekt (kilden til h&aelig;ndelsen)</I>
<I> *  &lt;li&gt; en streng (beskrivelse)</I>
<I> *  &lt;li&gt; et tal (et ID)</I>
<I> *  &lt;/ul&gt;</I>
<I> *  Du kan selvf&oslash;lgelig selv bestemme hvad objektet, strengen og tallet er,</I>
<I> *  hvis det er dine egne klasser der lytter efter h&aelig;ndelserne.</I>
<I> */</I>
public class SenderActionEvent extends Component
{
<I><B>  // ---------------------------- kopier herfra ----------------------------</B></I>
<I>   /** Lyttere til denne b&oslash;nne */</I>
   private ArrayList lyttere = new ArrayList(2);

<I>   /** Tilf&oslash;jer en lytter. Lytteren vil f&aring; kaldt metoden actionPerformed() n&aring;r</I>
<I>   *  der sker en h&aelig;ndelse.</I>
<I>   *  @param l Lytteren, der skal tilf&oslash;jes denne komponent.</I>
<I>   */</I>
<B>   public synchronized void addActionListener(ActionListener l)</B>
   {
     <SPAN LANG="da-DK">lyttere.add</SPAN>(l);
  }

<I>   /** Fjerner en lytter */</I>
<B>   public synchronized void removeActionListener(ActionListener l)</B>
   {
     <SPAN LANG="da-DK">lyttere.remove</SPAN>(l);
  }

<I>   /** Sender en h&aelig;ndelse til lyttere. Lytterne er de, der tidligere er blevet</I>
<I>   *  tilf&oslash;jet med kald til addActionListener()</I>
<I>   *  @see #addActionListener(ActionListener)</I>
<I>   *  @param h&aelig;ndelse H&aelig;ndelsen med de data, der skal sendes til lytterne</I>
<I>   */</I>
   protected void sendActionPerformedTilLytterne(ActionEvent h&aelig;ndelse)
   {
     for (Iterator i=<SPAN LANG="da-DK">lyttere.iterator</SPAN>(); i.hasNext(); )
     {
       ActionListener l = (ActionListener) <SPAN LANG="da-DK">i.next</SPAN>();
       <SPAN LANG="da-DK">l.actionPerformed</SPAN>(h&aelig;ndelse);
    }
  }
<I><B>  // ---------------------------- kopier hertil ----------------------------</B></I>

  public void paint(Graphics g)
  {
<I>    // opret en Action-h&aelig;ndelse, der kommer fra denne komponent og send den</I>
<I>    // brug konstrukt&oslash;ren new ActionEvent( <SPAN LANG="da-DK">afstanderobjekt</SPAN>, id, beskrivelse)</I>
    ActionEvent h&aelig;ndelse = new ActionEvent(this, 0, &quot;paint() kaldt&quot;);
    sendActionPerformedTilLytterne(h&aelig;ndelse);
  }
}</PRE><P CLASS="western">
Koden fra eksemplet kan kopieres og genbruges i dine egne
komponenter. 
</P>
<P CLASS="western">Action-h&aelig;ndelser er den mest anvendte
h&aelig;ndelsestype, men hvis du vil underst&oslash;tte en anden
type, skal du blot &aelig;ndre alle de steder, hvor der st&aring;r
'Action' (til f.eks. 'Mouse').</P>
<H2 CLASS="western">4.4 <a name='afsn4.4'></a>Ekstra eksempler</SPAN></H2>
<P CLASS="western">Her kommer nogle flere eksempler p&aring;
komponenter. Alle kan l&aelig;gges ind i et udviklingsv&aelig;rkt&oslash;js
palette og manipuleres fuldst&aelig;ndigt som de<SPAN LANG="da-DK">
forud installerede </SPAN>komponenter.</P>
<H3 CLASS="western">4.4.1 <a name='afsn4.4.1'></a>Rystetekst</H3>
<P CLASS="western">Den f&oslash;lgende b&oslash;nne viser en tekst,
der ryster. Det g&oslash;res ved, at den starter en separat tr&aring;d,
som 10 gange i sekundet kalder repaint() for at f&aring; komponenten
gentegnet. I paint() tegnes en tekst med en tilf&aelig;ldig
forskydning, og n&aring;r komponenten gentegnes 10 gange i sekundet,
ser det ud, som om teksten ryster.</P>
<P CLASS="western">Samtidig kan denne b&oslash;nne fort&aelig;lle
containeren, hvad dens foretrukne st&oslash;rrelse er (metoden
getPreferredSize() beskrevet i <a href='kapitel4.jsp#afsn4.2.3'>afsnit 4.2.3</a>). 
</P>
<P CLASS="western">Det sker ved at unders&oslash;ge den p&aring;g&aelig;ldende
tekst og finde ud af, hvor bred og h&oslash;j den er med den
p&aring;g&aelig;ldende skrifttype-st&oslash;rrelse (font-metrik).</P>
<PRE CLASS="kode-western">package vp;
import java.awt.*;
public class Rystetekst extends Component implements <SPAN LANG="da-DK">Runnable</SPAN>
{
  private String tekst = &quot;rystetekst&quot;;
  <B>public void setTekst(String t)</B> { tekst = t; foretrukneSt&oslash;rrelse = null; }
  <B>public String getTekst()</B> { return tekst; }

  Dimension foretrukneSt&oslash;rrelse = null;

  public Dimension getPreferredSize() {
    if (foretrukneSt&oslash;rrelse == null) try {
      <SPAN LANG="da-DK">FontMetrics</SPAN> fm = <SPAN LANG="da-DK">getFontMetrics</SPAN>(<SPAN LANG="da-DK">getFont</SPAN>());
      int <SPAN LANG="da-DK">tbr</SPAN> = <SPAN LANG="da-DK">fm.stringWidth</SPAN>(tekst);                         <I>// tekstbredde</I>
      int <SPAN LANG="da-DK">th&oslash;</SPAN> = <SPAN LANG="da-DK">fm.getHeight</SPAN>();                                <I>// teksth&oslash;jde</I>
      foretrukneSt&oslash;rrelse = new Dimension(tbr + 10, th&oslash; + 10); <I>// lidt ekstra</I>
    } catch (Exception e) {
      e.printStackTrace();
      foretrukneSt&oslash;rrelse = new Dimension(150,50);
    }
    return foretrukneSt&oslash;rrelse;
  }

  public Rystetekst()
  {
    <I>// hvis ikke i <SPAN LANG="da-DK">designfase</SPAN> s&aring; start en tr&aring;d der tager sig af opdateringen</I>
    if (!java.beans.Beans.isDesignTime())
    {
      Thread tr&aring;d = new Thread(this);
      <SPAN LANG="da-DK">tr&aring;d.setDaemon</SPAN>(true);    <I>// systemet skal ikke vente p&aring; at tr&aring;den stopper</I>
      <SPAN LANG="da-DK">tr&aring;d.start</SPAN>();            <I>// ny vil ny tr&aring;d starte nede i run()-metoden</I>
    }
  }

  <I>/** s&oslash;rger for at kalde repaint() regelm&aelig;ssigt */</I>
  public void run() {
    try {
      while (true) 
      {
        <SPAN LANG="da-DK">Thread.sleep</SPAN>(100);     <I>// vent 1/10 sekund</I>
        repaint();             <I>// gentegn komponenten</I>
      }
    } catch (Exception e) {}
  }

  public void paint(Graphics g)
  {
    <I>// tegn tekst p&aring; tilf&aelig;ldig x- og y-koordinat</I>
    g.drawString(tekst,            (int)(<SPAN LANG="da-DK">Math.random</SPAN>()*10), 
                       getHeight()-(int)(Math.random()*10));
  }
}</PRE><H3 CLASS="western">
4.4.2 <a name='afsn4.4.2'></a>Rulletekst</H3>
<P CLASS="western">Her er endnu en grafisk b&oslash;nne, der lader en
tekst rulle vandret hen over sk&aelig;rmen. Den har derfor
egenskaberne <I>tekst</I> og <I>fart</I>. Derudover er der
<I><SPAN LANG="da-DK">opdateringstid</SPAN></I>, der bestemmer, hvor
hyppigt den helst skal gentegnes p&aring; sk&aelig;rmen.</P>
<PRE CLASS="kode-western">package vp;
import java.awt.*;
import java.util.*;

public class Rulletekst extends Component implements Runnable
{
  <I>/** fort&aelig;l containeren hvad denne komponents foretrukne st&oslash;rrelse er */</I>
  public Dimension getPreferredSize() { return new Dimension(100,15); }

  <I>// Egenskaber</I>
  private String tekst = &quot;rulletekst &quot;;
  private int fart = 10;           <I>// antal punkter der rykkes i sekundet</I>
  private int opdateringstid = 50; <I>// antal millisekunder mellem hver gentegning</I>

  <B>public void setTekst(String t)</B> { tekst = t; klar = false; }
  <B>public String getTekst()</B> { return tekst; }

  <B>public void <SPAN LANG="da-DK">setFart</SPAN>(int f)</B> { fart = f; }
  <B>public int <SPAN LANG="da-DK">getFart</SPAN>()</B> { return fart; }

  <B>public void <SPAN LANG="da-DK">setOpdateringstid</SPAN>(int f)</B> {
    if (f&gt;=10) opdateringstid = f; <I>// tillad ikke under 10 <SPAN LANG="da-DK">msek</SPAN></I>
    else opdateringstid = 10;
  }

  <B>public int <SPAN LANG="da-DK">getOpdateringstid</SPAN>()</B> { return opdateringstid; }

  <I>// Interne variabler</I>
  private boolean klar = false;
  private int tbr, th&oslash;;            <I>// tekstens bredde og h&oslash;jde i punkter</I>
  private String <SPAN LANG="da-DK">tekstx</SPAN>;           <I>// teksten i det n&oslash;dvendige antal kopier</I>

  private synchronized void <SPAN LANG="da-DK">g&oslash;rKlar</SPAN>()
  {
    FontMetrics fm = getFontMetrics(getFont());
    tbr = fm.stringWidth(tekst);
    th&oslash; = fm.getHeight();
    Dimension d = getSize(); <I>// komponentens st&oslash;rrelse</I>
    int <SPAN LANG="da-DK">antalKopier</SPAN> = 2*<SPAN LANG="da-DK">d.width</SPAN>/tbr + 1;
    tekstx = tekst;
    while (antalKopier-- &gt;= 1) tekstx = tekstx + tekst;

    Thread tr&aring;d = new Thread(this);
    tr&aring;d.setDaemon(true);
    tr&aring;d.start();
    klar = true;
  }

  <I>/** s&oslash;rger for at kalde repaint() regelm&aelig;ssigt */</I>
  public void run() {
    try {
      while (true) {
        Thread.sleep(opdateringstid);
        repaint();
      }
    } catch (Exception e) {}
  }

  public void paint(Graphics g)
  {
    if (!klar) g&oslash;rKlar();

    int x = (int) (<SPAN LANG="da-DK">System.currentTimeMillis</SPAN>()*fart/1000);
    g.drawString(tekstx, x%tbr-tbr, th&oslash;);
  }
}</PRE><H3 CLASS="western">
4.4.3 <a name='afsn4.4.3'></a>Simpel kryptering</H3>
<P CLASS="western">Javab&oslash;nner beh&oslash;ver ikke at v&aelig;re
grafiske. Her er en ikke-grafisk b&oslash;nne, der kan kode tekster
med en gammel simpel metode (C&aelig;sar-kodning): Man erstatter a
med b, b med c, c med d, ... &aelig; med &aring; og &aring; med a. 
</P>
<P CLASS="western">&Oslash;nsker man en anden r&aelig;kkef&oslash;lge
af bogstaverne, &aelig;ndrer man egenskaben <I>kodestreng</I>. 
</P>
<P CLASS="western">Egenskaben <I>hop</I> bruges til at specificere
kodningens retning (1 svarer til indkodning, -1 til afkodning).</P>
<P CLASS="western">Metoden kod() udf&oslash;rer den faktiske kodning.
Den svarer ikke til en e<SPAN STYLE="font-style: normal">genskab (med
get- og set-metoder), og </SPAN>programm&oslash;ren, der anvender
b&oslash;nnen, m&aring; derfor selv s&oslash;rge for at lave koden,
der kalder metoden, n&aring;r der er brug for det.</P>
<PRE CLASS="kode-western">package vp;
public class Koder
{
  private String kodestreng = &quot;<SPAN LANG="da-DK">abcdefghijklmnopqrstuvwxyz&aelig;&oslash;&aring;</SPAN>&quot;;
  private int hop = 1;
  
  <B>public String <SPAN LANG="da-DK">getKodestreng</SPAN>()</B> { return kodestreng; }
  <B>public void <SPAN LANG="da-DK">setKodestreng</SPAN>(String ny)</B> { kodestreng = ny; }
  
  <B>public void <SPAN LANG="da-DK">setHop</SPAN>(int ny)</B> { hop = ny; }
  <B>public int <SPAN LANG="da-DK">getHop</SPAN>()</B> {  return hop; }

  public String kod(String s)
  {
    <SPAN LANG="da-DK">StringBuffer</SPAN> sb = new StringBuffer();
    for (int i=0; i&lt;s.length(); i++)
    {
      int p = <SPAN LANG="da-DK">kodestreng.indexOf</SPAN>( <SPAN LANG="da-DK">s.charAt</SPAN>(i) );
      if (p&gt;=0) {
        p = (p + hop + <SPAN LANG="da-DK">kodestreng.length</SPAN>()) % kodestreng.length();
        <SPAN LANG="da-DK">sb.append</SPAN>( <SPAN LANG="da-DK">kodestreng.charAt</SPAN>( p ));
      } else sb.append( s.charAt(i) );
    }
    return <SPAN LANG="da-DK">sb.toString</SPAN>();
  }
}</PRE>
<H3 CLASS="western" STYLE="">4.4.4 <a name='afsn4.4.4'></a>Eksempel
p&aring; brug af b&oslash;nnerne i et v&aelig;rkt&oslash;j</H3>
<P CLASS="western">P&aring; figuren herunder er vi i gang med at
designe et lille program med b&oslash;nnerne Rystetekst, Rulletekst
og Koder (der er lagt ind i 'Other'-fanen i<SPAN LANG="da-DK">
udviklingsv&aelig;rkt&oslash;jet JBuilders</SPAN> palette). Vi har
lige nu markeret b&oslash;nnen Rystetekst, og v&aelig;rkt&oslash;jet
viser derfor egenskaben <I>tekst</I> til h&oslash;jre. 
</P>
<P CLASS="western"><IMG SRC="bog5_html_m7f94c18e.png" NAME="Grafik2" ALIGN=BOTTOM BORDER=0></P>
<P CLASS="western">Da b&oslash;nnen Koder ikke er grafisk, vises den
ikke i v&aelig;rkt&oslash;jets design-fane. I stedet m&aring; man
v&aelig;lge den i struktur-tr&aelig;et (nederst til venstre er
instanserne indkoder og afkoder af Koder-b&oslash;nnen vist).</P>
<P CLASS="western">Programmet viser nogle ryste- og rulletekster og
to indtastningsfelter. Taster man noget i feltet til venstre og
trykker retur, vil teksten blive kodet med en Koder-b&oslash;nne og
resultatet vist i feltet til h&oslash;jre.</P>
<PRE CLASS="kode-western">import java.awt.*;
import java.awt.event.*;
import <SPAN LANG="da-DK">javax.swing.</SPAN>*;

public class <SPAN LANG="da-DK">BenytRystetekstRulletekstKoder</SPAN> extends Frame
{
<B>  Rystetekst rystetekst1 = new Rystetekst();</B>
<B>  Rystetekst rystetekst2 = new Rystetekst();</B>

<B>  Rulletekst rulletekst1 = new Rulletekst();</B>
<B>  Rulletekst rulletekst2 = new Rulletekst();</B>
<B>  Rulletekst rulletekst3 = new Rulletekst();</B>

<B>  Koder indkoder = new Koder();</B>
<B>  Koder afkoder = new Koder();</B>

  <SPAN LANG="da-DK">JTextField</SPAN> jTextField1 = new JTextField();
  JTextField jTextField2 = new JTextField();


  public BenytRystetekstRulletekstKoder() {
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }

  private void jbInit() throws Exception {
<B>    rulletekst1.setTekst(&quot;Hej, jeg hedder Jacob Nordfalk.   &quot;);</B>
<B>    rulletekst1.setForeground(<SPAN LANG="da-DK">Color.red</SPAN>);</B>
<B>    rulletekst1.setFart(-50);</B>
<B>    rulletekst1.setOpdateringstid(20);</B>
<B>    rulletekst2.setOpdateringstid(100);</B>
<B>    rulletekst3.setTekst(&quot;Indtast teksten i feltet til venstre herunder og &quot; +</B>
<B>    &quot;tryk retur. S&aring; kommer den indkodede tekst til h&oslash;jre. Du kan ogs&aring; taste &quot; +</B>
<B>    &quot;noget til h&oslash;jre og f&aring; det afkodet til venstre.&quot;);</B>
<B>    rulletekst3.setFart(-20);</B>

<B>    <SPAN LANG="da-DK">afkoder.setHop</SPAN>(-1);</B>

    jTextField1.setText(&quot;Tast her&quot;);
    jTextField1.addActionListener(new <SPAN LANG="da-DK">java.awt.event.ActionListener</SPAN>() {
      public void actionPerformed(ActionEvent e) {
        jTextField1_actionPerformed(e);
      }
    });
    jTextField2.setText(&quot;Her kommer koden&quot;);
    jTextField2.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        jTextField2_actionPerformed(e);
      }
    });
    
    this.setLayout(null);
    this.setSize(new Dimension(319, 247));

    this.add(rystetekst1, null);                         <I>// tilf&oslash;j til container</I>
    this.add(rystetekst2, null);
    this.add(rulletekst1, null);
    this.add(rulletekst2, null);
    this.add(rulletekst3, null);
    this.add(jTextField1, null);
    this.add(jTextField2, null);

    rystetekst1.setBounds(new Rectangle(15, 6, 111, 28)); <I>// placering p&aring; sk&aelig;rm</I>
    rystetekst2.setBounds(new Rectangle(183, 3, 112, 35));
    rulletekst1.setBounds(new Rectangle(81, 38, 152, 22));
    rulletekst2.setBounds(new Rectangle(0, 224, 320, 19));
    rulletekst3.setBounds(new Rectangle(12, 110, 290, 22));
    jTextField1.setBounds(new Rectangle(10, 137, 138, 25));
    jTextField2.setBounds(new Rectangle(160, 137, 137, 25));
  }

  void jTextField1_actionPerformed(ActionEvent e) {
    String s = <SPAN LANG="da-DK">e.getActionCommand</SPAN>();
<B>    s = <SPAN LANG="da-DK">indkoder.kod</SPAN>(s);</B>
<B>    jTextField2.setText(s);</B>
  }

  void jTextField2_actionPerformed(ActionEvent e) {
    String s = e.getActionCommand();
<B>    s = <SPAN LANG="da-DK">afkoder.kod</SPAN>(s);</B>
<B>    jTextField1.setText(s);</B>
  }

  public static void main(String[] arg) {
    BenytRystetekstRulletekstKoder v = new BenytRystetekstRulletekstKoder();
    <SPAN LANG="da-DK">v.setSize</SPAN>(400,400);
    <SPAN LANG="da-DK">v.setVisible</SPAN>(true);
  }
}</PRE><H2 CLASS="western" STYLE="">
4.5 <a name='afsn4.5'></a>Opgaver</SPAN></H2>
<P CLASS="western">I alle opgaverne herunder er det underforst&aring;et,
at du s&oslash;rger for at afpr&oslash;ve dine ting ved at lave sm&aring;
programmer, der bruger komponenterne. 
</P>
<P CLASS="western">Vejledende l&oslash;sninger p&aring; nogen af
opgaverne findes i n&aelig;ste afsnit.</P>
<H4 CLASS="western">Grafiske komponenter</H4>
<OL>
  <LI><P CLASS="western">Ret i b&oslash;nnen GentagTekst, og indf&oslash;r
  egenskaben <I>antal</I>, der bestemmer, hvor mange gange teksten
  skal tegnes.</P>
  <LI><P CLASS="western">Ret b&oslash;nnen, s&aring; den fort&aelig;ller
  sin foretrukne st&oslash;rrelse til containeren (se <a href='kapitel4.jsp#afsn4.2.3'>afsnit 4.2.3</a>,
  St&oslash;rrelsen af en grafisk komponent).</P>
  <LI><P CLASS="western">Kig p&aring; b&oslash;nnen Rystetekst i
  <a href='kapitel4.jsp#afsn4.4.1'>afsnit 4.4.1</a>. Hvad hvis man skulle kunne styre b&oslash;nnens
  opdateringstid, der bestemmer, hvor hurtigt teksten ryster
  (tidsrummet mellem to gentegninger)? Indf&oslash;r egenskaben
  <I>opdateringstid</I> i b&oslash;nnen, og brug den.</P>
  <LI><P CLASS="western">Blandt AWT-komponenterne mangler der en
  komponent, der kan vise et billede<A CLASS="sdfootnoteanc" NAME="sdfootnote4anc" HREF="#sdfootnote4sym"><SUP>4</SUP></A>.<BR>Lav
  en, f.eks. med udgangspunkt i GentagTekst.java. Defin&eacute;r
  egenskaben <BR><I>filnavn</I>   en streng, der beskriver, hvor
  billedet er<BR>Billeder kan hentes med f.eks.:  <BR><FONT FACE="Courier, monospace"><FONT SIZE=1 STYLE="font-size: 8pt"><SPAN STYLE="font-weight: medium"><SPAN STYLE="background: #d9d9d9">  Image
  i = Toolkit.getDefaultToolkit()<SPAN LANG="da-DK">.</SPAN><FONT FACE="Courier, monospace"><FONT SIZE=1 STYLE="font-size: 8pt"><SPAN STYLE="font-weight: medium"><SPAN STYLE="background: #d9d9d9"><SPAN LANG="da-DK"></SPAN></SPAN></SPAN></FONT></FONT><SPAN LANG="da-DK">getImage</SPAN>(&quot;<SPAN LANG="da-DK">hej.jpg</SPAN>&quot;);
  <BR>  <SPAN LANG="da-DK">g.drawImage</SPAN>(i, 10, 10, this);</SPAN></SPAN></FONT></FONT><BR>Her
  skal filen hej.jpg ligge samme sted, som programmet udf&oslash;res
  (ellers pr&oslash;v at kopiere billedet til nogle forskellige steder
  i filstrukturen, indtil programmet 'f&aring;r fat' i det).</P>
  <LI><P CLASS="western">Lav en grafisk komponent, der viser en
  animation, dvs. et antal billeder vist i kort r&aelig;kkef&oslash;lge
  efter hinanden. Kig p&aring; <SPAN LANG="da-DK">Rulletekst.java</SPAN>
  for nogle id&eacute;er.<BR>Har du ikke lavet den forrige opgave, s&aring;
  tag udgangspunkt i Swing-komponenten <SPAN LANG="da-DK">JLabel</SPAN>
  (der ud over en tekst ogs&aring; kan vise et billede).</P>
</OL>
<H4 CLASS="western">Webserver-komponent</H4>
<OL>
  <LI><P CLASS="western">Lav en (ikke-grafisk) webserver-b&oslash;nne.
  Tag udgangspunkt klasserne <SPAN LANG="da-DK">FlertraadetHjemmesidevaert</SPAN>
  og Anmodning fra <A CLASS="western" HREF="http://javabog.dk/OOP/eksempler/kapitel_17/">http://javabog.dk/OOP/eksempler/kapitel_17/</A>
  (beskrevet i <SPAN STYLE="font-weight: medium"><A CLASS="western" HREF="http://javabog.dk/OOP/kapitel16.html">http://javabog.dk/OOP/kapitel16.html</A></SPAN>
  og det efterf&oslash;lgende kapitel).<BR>Den skal have
  egenskaberne:<BR><I>port</I><SPAN STYLE="font-style: normal">  angiver,
  hvilken port <SPAN LANG="da-DK">serveren</SPAN> skal lytte p&aring;</SPAN>
  (f.eks. 8080)<BR><I>aktiv</I><SPAN STYLE="font-style: normal">  om
  den er aktiv, dvs. om den venter p&aring; anmodninger
  (true/false)<BR>Lad den f&oslash;rst bare svare med den samme tekst
  uafh&aelig;ngig af sp&oslash;rgsm&aring;let.<BR>Opret et
  testprogram, der anvender b&oslash;nnen og s&aelig;tter dens
  egenskaber.</SPAN></P>
  <LI><P CLASS="western"><SPAN STYLE="font-style: normal">Lad den
  underst&oslash;tte abonnement p&aring; Action-h&aelig;ndelser (se
  <a href='kapitel4.jsp#afsn4.3.5'>afsnit 4.3.5</a>), p&aring; en s&aring;dan m&aring;de, at der sendes en
  h&aelig;ndelse, hver gang der kommer en anmodning.<BR>&AElig;ndr i
  testprogrammet s&aring; det abonnerer p&aring; h&aelig;ndelsen og
  skriver ud, n&aring;r den indtr&aelig;ffer.</SPAN></P>
  <LI><P CLASS="western"><SPAN STYLE="font-style: normal">Lad b&oslash;nnen
  kunne l&aelig;se filer fra filsystemet og sende til brugeren.
  Defin&eacute;r egenskaben<BR></SPAN><I>rod</I><SPAN STYLE="font-style: normal">  </SPAN>sti
  til rodkataloget, hvor HTML-siderne, der kan hentes, er (f.eks.
  C:\HTML).</P>
</OL>

<H2 CLASS="western" STYLE="">4.6 <a name='afsn4.6'></a>L&oslash;sninger</SPAN></H2>

	    Dette afsnit er ikke omfattet af Åben Dokumentslicens.<br>
	    Du skal <a href="/index_VP.html#bestil">købe</a> bogen for at
	    måtte læse dette afsnit.

  <form action="http://javabog.dk/VP/kapitel4.jsp#afsn4.6">
  <input type='checkbox' name='vis' value='4.6'>Jeg erklærer, at jeg allerede har købt bogen<br />
  <input type='checkbox' name='vis' value='4.6'>Jeg lover at anskaffe den i nær fremtid.<br />
  <input type='submit' value='Vis mig dette afsnit'>
  </form>

	  <H3 CLASS="western">4.6.1 <a name='afsn4.6.1'></a>Grafisk komponent: GentagTekst</H3>

	    Dette afsnit er ikke omfattet af Åben Dokumentslicens.<br>
	    Du skal <a href="/index_VP.html#bestil">købe</a> bogen for at
	    måtte læse dette afsnit.

  <form action="http://javabog.dk/VP/kapitel4.jsp#afsn4.6.1">
  <input type='checkbox' name='vis' value='4.6.1'>Jeg erklærer, at jeg allerede har købt bogen<br />
  <input type='checkbox' name='vis' value='4.6.1'>Jeg lover at anskaffe den i nær fremtid.<br />
  <input type='submit' value='Vis mig dette afsnit'>
  </form>

	  <H3 CLASS="western">4.6.2 <a name='afsn4.6.2'></a>Grafisk komponent: Billede</H3>

	    Dette afsnit er ikke omfattet af Åben Dokumentslicens.<br>
	    Du skal <a href="/index_VP.html#bestil">købe</a> bogen for at
	    måtte læse dette afsnit.

  <form action="http://javabog.dk/VP/kapitel4.jsp#afsn4.6.2">
  <input type='checkbox' name='vis' value='4.6.2'>Jeg erklærer, at jeg allerede har købt bogen<br />
  <input type='checkbox' name='vis' value='4.6.2'>Jeg lover at anskaffe den i nær fremtid.<br />
  <input type='submit' value='Vis mig dette afsnit'>
  </form>

	  <H3 CLASS="western" STYLE="">
4.6.3 <a name='afsn4.6.3'></a>Webserver-komponent</H3>

	    Dette afsnit er ikke omfattet af Åben Dokumentslicens.<br>
	    Du skal <a href="/index_VP.html#bestil">købe</a> bogen for at
	    måtte læse dette afsnit.

  <form action="http://javabog.dk/VP/kapitel4.jsp#afsn4.6.3">
  <input type='checkbox' name='vis' value='4.6.3'>Jeg erklærer, at jeg allerede har købt bogen<br />
  <input type='checkbox' name='vis' value='4.6.3'>Jeg lover at anskaffe den i nær fremtid.<br />
  <input type='submit' value='Vis mig dette afsnit'>
  </form>

	  
<H2 CLASS="western" STYLE="">4.7 <a name='afsn4.7'></a>Avanceret</SPAN></H2>

	    Dette afsnit er ikke omfattet af Åben Dokumentslicens.<br>
	    Du skal <a href="/index_VP.html#bestil">købe</a> bogen for at
	    måtte læse dette afsnit.

  <form action="http://javabog.dk/VP/kapitel4.jsp#afsn4.7">
  <input type='checkbox' name='vis' value='4.7'>Jeg erklærer, at jeg allerede har købt bogen<br />
  <input type='checkbox' name='vis' value='4.7'>Jeg lover at anskaffe den i nær fremtid.<br />
  <input type='submit' value='Vis mig dette afsnit'>
  </form>

	  <H3 CLASS="western">4.7.1 <a name='afsn4.7.1'></a>En komponent til at tegne kurver</H3>

	    Dette afsnit er ikke omfattet af Åben Dokumentslicens.<br>
	    Du skal <a href="/index_VP.html#bestil">købe</a> bogen for at
	    måtte læse dette afsnit.

  <form action="http://javabog.dk/VP/kapitel4.jsp#afsn4.7.1">
  <input type='checkbox' name='vis' value='4.7.1'>Jeg erklærer, at jeg allerede har købt bogen<br />
  <input type='checkbox' name='vis' value='4.7.1'>Jeg lover at anskaffe den i nær fremtid.<br />
  <input type='submit' value='Vis mig dette afsnit'>
  </form>

	  <H3 CLASS="western" STYLE="">4.7.2 <a name='afsn4.7.2'></a>Repr&aelig;sentation
af funktioner</H3>

	    Dette afsnit er ikke omfattet af Åben Dokumentslicens.<br>
	    Du skal <a href="/index_VP.html#bestil">købe</a> bogen for at
	    måtte læse dette afsnit.

  <form action="http://javabog.dk/VP/kapitel4.jsp#afsn4.7.2">
  <input type='checkbox' name='vis' value='4.7.2'>Jeg erklærer, at jeg allerede har købt bogen<br />
  <input type='checkbox' name='vis' value='4.7.2'>Jeg lover at anskaffe den i nær fremtid.<br />
  <input type='submit' value='Vis mig dette afsnit'>
  </form>

	  <H3 CLASS="western" STYLE="">
4.7.3 <a name='afsn4.7.3'></a>Fortolkning af strenge til funktioner</H3>

	    Dette afsnit er ikke omfattet af Åben Dokumentslicens.<br>
	    Du skal <a href="/index_VP.html#bestil">købe</a> bogen for at
	    måtte læse dette afsnit.

  <form action="http://javabog.dk/VP/kapitel4.jsp#afsn4.7.3">
  <input type='checkbox' name='vis' value='4.7.3'>Jeg erklærer, at jeg allerede har købt bogen<br />
  <input type='checkbox' name='vis' value='4.7.3'>Jeg lover at anskaffe den i nær fremtid.<br />
  <input type='submit' value='Vis mig dette afsnit'>
  </form>

	  <H3 CLASS="western">
4.7.4 <a name='afsn4.7.4'></a>Layout-manageres virkem&aring;de</H3>

	    Dette afsnit er ikke omfattet af Åben Dokumentslicens.<br>
	    Du skal <a href="/index_VP.html#bestil">købe</a> bogen for at
	    måtte læse dette afsnit.

  <form action="http://javabog.dk/VP/kapitel4.jsp#afsn4.7.4">
  <input type='checkbox' name='vis' value='4.7.4'>Jeg erklærer, at jeg allerede har købt bogen<br />
  <input type='checkbox' name='vis' value='4.7.4'>Jeg lover at anskaffe den i nær fremtid.<br />
  <input type='submit' value='Vis mig dette afsnit'>
  </form>

	  <H3 CLASS="western" STYLE="">4.7.5 <a name='afsn4.7.5'></a>&Oslash;velse:
Samspil med layout-manager</H3>

	    Dette afsnit er ikke omfattet af Åben Dokumentslicens.<br>
	    Du skal <a href="/index_VP.html#bestil">købe</a> bogen for at
	    måtte læse dette afsnit.

  <form action="http://javabog.dk/VP/kapitel4.jsp#afsn4.7.5">
  <input type='checkbox' name='vis' value='4.7.5'>Jeg erklærer, at jeg allerede har købt bogen<br />
  <input type='checkbox' name='vis' value='4.7.5'>Jeg lover at anskaffe den i nær fremtid.<br />
  <input type='submit' value='Vis mig dette afsnit'>
  </form>

	  <H3 CLASS="western">4.7.6 <a name='afsn4.7.6'></a>Opgave: Adresseindtastningskomponent</H3>

	    Dette afsnit er ikke omfattet af Åben Dokumentslicens.<br>
	    Du skal <a href="/index_VP.html#bestil">købe</a> bogen for at
	    måtte læse dette afsnit.

  <form action="http://javabog.dk/VP/kapitel4.jsp#afsn4.7.6">
  <input type='checkbox' name='vis' value='4.7.6'>Jeg erklærer, at jeg allerede har købt bogen<br />
  <input type='checkbox' name='vis' value='4.7.6'>Jeg lover at anskaffe den i nær fremtid.<br />
  <input type='submit' value='Vis mig dette afsnit'>
  </form>

	  <H3 CLASS="western" STYLE="">4.7.7 <a name='afsn4.7.7'></a>L&oslash;sning:
Adresseindtastningskomponent</H3>

	    Dette afsnit er ikke omfattet af Åben Dokumentslicens.<br>
	    Du skal <a href="/index_VP.html#bestil">købe</a> bogen for at
	    måtte læse dette afsnit.

  <form action="http://javabog.dk/VP/kapitel4.jsp#afsn4.7.7">
  <input type='checkbox' name='vis' value='4.7.7'>Jeg erklærer, at jeg allerede har købt bogen<br />
  <input type='checkbox' name='vis' value='4.7.7'>Jeg lover at anskaffe den i nær fremtid.<br />
  <input type='submit' value='Vis mig dette afsnit'>
  </form>

	  
<DIV ID="sdfootnote1">
  <P CLASS="sdfootnote-western"><A CLASS="sdfootnotesym" NAME="sdfootnote1sym" HREF="#sdfootnote1anc">1</A>En
  anonym klasse er en klasse uden navn, som der oprettes netop &eacute;t
  objekt ud fra der, hvor den defineres (alts&aring; en unavngiven
  lokal klasse). Mere information om anonyme klasser kan f.eks. findes
  i kapitlet 'Avancerede klasser' i 'Objektorienteret programmering i
  Java' af Jacob Nordfalk, som ogs&aring; kan l&aelig;ses p&aring;
  http://javabog.dk</P>
</DIV>
<DIV ID="sdfootnote2">
  <P CLASS="sdfootnote-western"><A CLASS="sdfootnotesym" NAME="sdfootnote2sym" HREF="#sdfootnote2anc">2</A>Dette
  skulle svare til et type-library i Windows' COM-verden.</P>
</DIV>
<DIV ID="sdfootnote3">
  <P CLASS="sdfootnote-western"><A CLASS="sdfootnotesym" NAME="sdfootnote3sym" HREF="#sdfootnote3anc">3</A>Normalt
  sendes der ikke h&aelig;ndelser, fordi paint() kaldes. Se klassen
  Kontomodel i <a href='kapitel19.jsp#afsn19.3.1'>afsnit 19.3.1</a> for et mere realistisk eksempel.</P>
</DIV>
<DIV ID="sdfootnote4">
  <P CLASS="sdfootnote-western"><A CLASS="sdfootnotesym" NAME="sdfootnote4sym" HREF="#sdfootnote4anc">4</A>Dette
  g&aelig;lder ikke Swing, hvor man kan s&aelig;tte billeder p&aring;
  n&aelig;sten alle komponenterne. For eksempel kan JLabel ud over en
  tekst ogs&aring; vise et billede.</P>
</DIV>
<DIV ID="sdfootnote5">
  <P CLASS="sdfootnote-western"><A CLASS="sdfootnotesym" NAME="sdfootnote5sym" HREF="#sdfootnote5anc">5</A>Dette
  er et eksempel p&aring; Rekursiv Komposition (se <a href='kapitel18.jsp#afsn18.5'>afsnit 18.5</a>).</P>
</DIV>

<a href='http://javabog.dk/'>javabog.dk</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='kapitel3.jsp'>&lt;&lt; forrige</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='indhold.jsp'>indhold</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='kapitel5.jsp'>n&aelig;ste &gt;&gt;</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='kode/'>programeksempler</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='../index_VP.html'>om bogen</a>
<hr>
<font size=-2>http://javabog.dk/ - <b></b> af Jacob Nordfalk.
<br>
  Licens og kopiering under <a href='http://www.linuxbog.dk/licens.html'>&Aring;ben Dokumentlicens</a> (&Aring;DL)
  hvor intet andet er nævnt (71% af værket).
</font>
<br>
Ønsker du at se de sidste 29% af dette værk (362838 tegn)
skal du købe bogen. Så får du pæne figurer og layout, stikordsregister og en trykt bog med i købet.
<!-- netlæser: Wget/1.10, autoHent: true  -->
     

</body>
</html>
