



<html>
<head>
  <title>javabog.dk -  - Grafiske brugergr&aelig;nseflader (Swing)</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='kapitel5.jsp'>&lt;&lt; forrige</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='indhold.jsp'>indhold</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='kapitel7.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="">6 <a name='afsn6'></a>Grafiske
brugergr&aelig;nseflader (Swing)</H1>
<DIV ID="Indholdsfortegnelse11">
  <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>6.1
  Introduktion til Swing  100</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">6.1.1
  Eksempel p&aring; forskelle mellem Swing og AWT  101</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>6.2
  MVC i Swing- og AWT-komponenter  102</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">6.2.1
  AWT-komponenter  102</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">6.2.2
  Swing-komponenter  102</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>6.3
  Datamodellen i Swing-komponenter  103</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">6.3.1
  Tekstfelter (interfacet Document)  103</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">6.3.2
  Tabeller (interfacet TableModel)  104</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">6.3.3
  Knapper (interfacet ButtonModel)  105</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">6.3.4
  Andre komponenter  106</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">6.3.5
  Opgaver  106</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">6.3.6
  L&oslash;sning  107</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>6.4
  Pr&aelig;sentationsdelen i Swing  110</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">6.4.1
  Lister (ListCellRenderer)  110</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">6.4.2
  Eksempel: Pr&aelig;sentation af skrifter i en liste  111</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">6.4.3
  Tabeller (TableCellRenderer)  113</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">6.4.4
  Tr&aelig;er (TreeCellRenderer)  114</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">6.4.5
  Opgaver  114</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>6.5
  Kontroldelen af Swing-komponenter  115</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">6.5.1
  Tabeller (TableCellEditor)  115</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">6.5.2
  Tr&aelig;er (TreeCellEditor)  115</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">6.5.3
  Standardredigering med DefaultCellEditor  115</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>6.6
  Eksempler  116</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">6.6.1
  SwingSet2-demo af JTable  116</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">6.6.2
  Eksempel med JTable  117</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>6.7
  Avanceret: Udseendet af Swing  119</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">6.7.1
  Swing-komponenters standardudseender  119</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">6.7.2
  Andre udseender  119</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">6.7.3
  Kunststoff-udseendet  119</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">6.7.4
  Alloys-udseendet  120</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">6.7.5
  Opgaver  120</FONT></FONT></P>
</DIV>

<P CLASS="kapiteloversigt-western">Det er en fordel at have l&aelig;st
den f&oslash;rste del af <a href='kapitel19.jsp'>kapitel 19</a> for at have et kendskab til Model-View-Controller-arkitekturen.</P>
<P CLASS="western" STYLE="">Dette kapitel
handler hovedsageligt om de ting i Swing, der er umiddelbart sv&aelig;re
at forst&aring;. Det b<SPAN STYLE="font-weight: medium">ehandler
nogle af de mere avancerede aspekter af brugergr&aelig;nseflader og
Swing, som bl.a. JTable og MVC (Model-View-Controller-arkitekturen,
beskrevet i dybden i <a href='kapitel19.jsp'>kapitel 19</a>).</SPAN></P>
<P CLASS="western">En mere grundl&aelig;ggende (om end lidt gammel)
introduktion finder man i Kristian Hansens bog 'Avanceret
Java-programmering', der kan hentes gratis p&aring;
<SPAN STYLE="font-weight: medium"><A CLASS="western" HREF="http://bog.ing.dk/">http://<SPAN LANG="da-DK">bog.ing.dk</SPAN>/</A></SPAN>.</P>
<H2 CLASS="western">6.1 <a name='afsn6.1'></a>Introduktion til Swing</SPAN></H2>
<P CLASS="western">I Java 1.2 blev et nyt s&aelig;t komponenter f&oslash;jet
til standardbibliotekerne. De svarer meget til AWT-komponenterne, men
de er <SPAN LANG="da-DK">letv&aelig;gtkomponenter</SPAN>, dvs. de er
programmeret helt i Java og er derfor mindre afh&aelig;ngige af det
underliggende styresystem. 
</P>
<P CLASS="western">De kaldes Swing-komponenter og findes i pakken
javax.swing, og de starter alle med et J i klassenavnet, f.eks.
JButton, <SPAN LANG="da-DK">JCheckBox</SPAN>, <SPAN LANG="da-DK">JRadioButton</SPAN>,
JLabel, <SPAN LANG="da-DK">JList</SPAN>, JTextField, <SPAN LANG="da-DK">JTextArea</SPAN>,
JPanel, <SPAN LANG="da-DK">JApplet</SPAN> og JFrame. 
</P>
<P CLASS="western">Der er ogs&aring; flere komponenter, som ikke
findes i java.awt: <SPAN LANG="da-DK">JComboBox</SPAN>,
<SPAN LANG="da-DK">JToggleBotton</SPAN>, JTable (en regneark-lignende
komponent til at vise og manipulere <SPAN LANG="da-DK">tabeldata</SPAN>),
<SPAN LANG="da-DK">JTree</SPAN> (viser en tr&aelig;struktur ligesom
stifinderen i Windows) og <SPAN LANG="da-DK">JTextPane</SPAN> (kan
vise og redigere tekst med formatering og indlejrede billeder,
herunder HTML- og RTF-dokumenter).</P>
<P CLASS="western">Her er et klassediagram over de vigtigste
Swing-komponenter:</P>
<P CLASS="western"><IMG SRC="bog7_html_m4e097314.gif" NAME="Graphic8" ALIGN=BOTTOM BORDER=0></P>
<P CLASS="western">Yderst til venstre ses AWT-klasserne Container,
Window, Frame, Panel og Applet. Resten er Swing-komponenter, og det
ses, hvordan AWT-komponenterne alle har en pendant i Swing med et
foranstillet J.</P>
<P CLASS="western">For at undg&aring; <SPAN LANG="da-DK">blinkeri</SPAN>
bruger alle Swing-containere som standard dobbelt tegnebuffer (eng.:
double buffering, hvor komponenterne, n&aring;r de skal gentegnes,
ikke tegnes direkte p&aring; sk&aelig;rmen, men i en separat
grafikbuffer, som derefter kopieres ind p&aring; sk&aelig;rmen.</P>
<H3 CLASS="western" STYLE="">6.1.1 <a name='afsn6.1.1'></a>Eksempel
p&aring; forskelle mellem Swing og AWT</H3>
<P CLASS="western">Dette eksempel illustrerer de v&aelig;sentligste
forskelle mellem Swing og AWT (forskellene er markeret med  fed):</P>
<PRE CLASS="kode-western">import java.awt.*;
<B>import javax.swing.*;</B>

public class <SPAN LANG="da-DK">SwingVindue</SPAN> <B>extends JFrame</B>
{
  <B>JLabel</B> <SPAN LANG="da-DK">labelHvadErDitNavn</SPAN> = new <B>JLabel</B>();
  <B>JTextField</B> textFieldNavn = new <B>JTextField</B>();
  <B>JButton</B> <SPAN LANG="da-DK">buttonOpdater</SPAN> = new <B>JButton</B>();
  <B>JTextArea</B> <SPAN LANG="da-DK">textAreaHilsen</SPAN> = new <B>JTextArea</B>();

  public void paint(Graphics g) {
    <I>// vigtigt! Kald den oprindelige paint() s&aring; Swing-komponenter bliver tegnet</I>
    <B><SPAN LANG="da-DK">super.paint</SPAN>(g)</B>;

    g.drawLine(0,0,50,50);
    <SPAN LANG="da-DK">g.fillOval</SPAN>(5,20,300,30);
    <SPAN LANG="da-DK">g.setColor</SPAN>(<SPAN LANG="da-DK">Color.green</SPAN>);
    String navn = textFieldNavn.getText();
    for (int i=0; i&lt;50; i=i+10)
      g.drawString(&quot;Hej &quot;+navn+&quot; !&quot;,100+i,30+i);
  }

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

  private void jbInit() throws Exception {
    <I>// Swing-komponenter tillader HTML-koder i deres tekst:</I>
    <SPAN LANG="da-DK">labelHvadErDitNavn.setText</SPAN>(<B>&quot;&lt;html&gt;&lt;b&gt;Hvad er&lt;/b&gt; dit &lt;i&gt;navn&lt;/i&gt;?&lt;/html&gt;&quot;</B>);
    <SPAN LANG="da-DK">labelHvadErDitNavn.setBounds</SPAN>(new Rectangle(15, 69, 108, 15));
    textFieldNavn.setText(&quot;Jacob&quot;);
    textFieldNavn.setBounds(new Rectangle(129, 61, 95, 29));

    <SPAN LANG="da-DK">buttonOpdater.setText</SPAN>(<B>&quot;&lt;html&gt;&lt;font size=+1&gt;op&lt;/font&gt;da&lt;u&gt;ter&lt;/u&gt;!&lt;/html&gt;&quot;</B>);
    <SPAN LANG="da-DK">buttonOpdater.setBounds</SPAN>(new Rectangle(231, 60, 91, 32));
    <SPAN LANG="da-DK">textAreaHilsen.setText</SPAN>(&quot;Her kommer en tekst...&quot;);
    <SPAN LANG="da-DK">textAreaHilsen.setBounds</SPAN>(new Rectangle(6, 102, 316, 78));

    <I>// vigtigt! Tilf&oslash;j komponenterne til &quot;content pane&quot; p&aring; en Swing-container</I>
    <SPAN LANG="da-DK">this.<B>getContentPane</B></SPAN><B>()</B><SPAN LANG="da-DK">.setLayout</SPAN>(null);
    this.<B>getContentPane()</B><SPAN LANG="da-DK">.add</SPAN>(labelHvadErDitNavn, null);
    this.<B>getContentPane()</B>.add(textAreaHilsen, null);
    this.<B>getContentPane()</B>.add(buttonOpdater, null);
    this.<B>getContentPane()</B>.add(textFieldNavn, null);
  }

  public static void main(String[] arg) {
    SwingVindue vindue = new SwingVindue();
    vindue.setSize(350,120);
    vindue.setVisible(true);
  }
}</PRE><P CLASS="western" ALIGN=CENTER>
<IMG SRC="bog7_html_madc13c8.png" NAME="Grafik31" ALIGN=MIDDLE BORDER=0></P>
<P CLASS="western">Som det ses af eksemplet, underst&oslash;tter
Swing-komponenter visning af HTML-kode, s&aring; man kan f&aring;
knapper og etiketter, hvor dele af teksten er f.eks. fed, kursiv
eller af en anden st&oslash;rrelse.</P>
<P CLASS="western">Bruger man Swing-komponenter og samtidig har
defineret paint()-metoden, skal man huske at kalde den oprindelige
paint()-metode, ellers &quot;forsvinder&quot; Swing-komponenterne:</P>
<PRE CLASS="kode-western">  public void paint(Graphics g) 
  {
    <I>// vigtigt! Kald den oprindelige paint() s&aring; Swing-komponenter bliver tegnet</I>
    super.paint(g);

<I>    // herunder kommer vores egen tegningskode</I>
  }</PRE><P CLASS="western">
Det skyldes, at Swing-komponenter bliver tegnet fra containerens
(superklassens) paint()-metode. Bliver paint() ikke kaldt i
superklassen, bliver Swing-komponenterne ikke tegnet.</P>
<P CLASS="western">En anden vigtig forskel er, at man ikke f&oslash;jer
komponenter direkte til containeren, men til dens &quot;content
pane&quot;, med this.getContentPane().add( komponent ). 
</P>
<P CLASS="western">I AWT skrev man blot this.add( komponent ).</P>
<H2 CLASS="western">6.2 <a name='afsn6.2'></a>MVC i Swing- og AWT-komponenter</SPAN></H2>
<P CLASS="western">Selvom MVC (Model-View-Controller-arkitekturen
beskrevet i <a href='kapitel19.jsp'>kapitel 19</a>) egentlig er beregnet p&aring; at adskille et
programs logik fra dets brugergr&aelig;nseflade, kan tankegangen ogs&aring;
bruges internt i en grafisk komponent til at adskille de data, som
komponenten repr&aelig;senterer, fra fremvisningen og &aelig;ndringen
af dem.</P>
<P CLASS="western">Lad os se p&aring; eksempelvis et indtastningsfelt
(TextField eller JTextField):</P>
<UL>
  <LI><P CLASS="western"><B>Modellen</B> er selve teksten, brugeren
  redigerer i. 
  </P>
  <LI><P CLASS="western"><B>Pr&aelig;sentationen</B> er at vise
  teksten p&aring; sk&aelig;rmen.</P>
  <LI><P CLASS="western"><B>Kontroldelen</B> er fortolkningen af
  <SPAN LANG="da-DK">tastetryk</SPAN> og at oms&aelig;tte dem til
  tegn, der bliver sat ind i teksten.</P>
</UL>
<H3 CLASS="western">6.2.1 <a name='afsn6.2.1'></a>AWT-komponenter</H3>
<P CLASS="western">AWT-komponenterne, de oprindelige simple
komponenter, som Java blev f&oslash;dt med, fungerer som bro til
platformens egne grafiske komponenter, s&aring;dan at n&aring;r et
program opretter f.eks. et Button-objekt, vil der faktisk blive
oprettet en Windows-knap under Windows, en Linux-knap under Linux, en
MacOS-knap p&aring; Macintosh osv.. Button-objektet vil s&aring;
fungere som <SPAN LANG="da-DK">platformsuafh&aelig;ngig</SPAN> facade
ned mod den meget <SPAN LANG="da-DK">platformsspecifikke</SPAN> knap.</P>
<P CLASS="western">Det er derfor ikke muligt at p&aring;virke,
hvordan en AWT-komponent virker, og model, pr&aelig;sentation og
kontrol-del er uadskillelige. Det g&oslash;r dem relativt simple at
arbejde med, men ogs&aring; relativt ufleksible, hvis man skulle
&oslash;nske at &aelig;ndre dem, s&aring; de virker lidt anderledes.</P>
<P CLASS="western">F.eks. er det meget besv&aelig;rligt (hvis ikke
umuligt) at have to tekstfelter, der redigerer i den samme tekst,
eller at lave et tekstfelt, som kun viser store bogstaver.</P>
<H3 CLASS="western">6.2.2 <a name='afsn6.2.2'></a>Swing-komponenter</H3>
<P CLASS="western">Swing-komponenter er implementeret i ren Java, og
derfor har det v&aelig;ret muligt at g&oslash;re dem langt mere
fleksible end AWT-komponenterne.</P>
<P CLASS="western">I Swing-komponenterne er datamodellen skilt ud fra
komponenten. Det vil sige, at programm&oslash;ren har mulighed for at
selv bestemme, hvilket objekt der skal bruges som datamodel.
Pr&aelig;sentationen og kontroldelen har man ogs&aring; adgang til,
<SPAN LANG="da-DK">omend</SPAN> mere begr&aelig;nset.</P>
<H2 CLASS="western">6.3 <a name='afsn6.3'></a>Datamodellen i Swing-komponenter</SPAN></H2>
<P CLASS="western">Modellen i en komponent er de data, som
komponenten repr&aelig;senterer. Hvilken slags model der anvendes
afh&aelig;nger meget af komponenten.</P>
<H3 CLASS="western">6.3.1 <a name='afsn6.3.1'></a>Tekstfelter (interfacet Document)</H3>
<P CLASS="western">I JTextField, JTextArea og de andre
<SPAN LANG="da-DK">tekstredigeringsfelter</SPAN> er datamodellen et
objekt af typen Document, og l&aelig;ses hhv. s&aelig;ttes med
metoderne <SPAN LANG="da-DK">getDocument</SPAN>() og <SPAN LANG="da-DK">setDocument</SPAN>():</P>
<PRE CLASS="kode-western">public Document getDocument()
public void setDocument(Document doc)</PRE><P CLASS="western">
Document er et interface, der er ret indviklet af finde rundt i,
fordi det er beregnet til ogs&aring; at underst&oslash;tte RTF- og
HTML-formaterede dokumenter (<SPAN LANG="da-DK">JEditorPane</SPAN> og
JTextPane), s&aring; det vil vi ikke beskrive i detaljer.</P>
<H4 CLASS="western">Eksempel: To tekstfelter, der deler det samme
dokument</H4>
<P CLASS="western">Har man to tekstfelter...</P>
<PRE CLASS="kode-western">  JTextField jTextField1 = new JTextField();
  JTextField jTextField2 = new JTextField();</PRE><P CLASS="western">
kan man f&aring; dem til at redigere <I>i den samme tekst</I> ved at
s&aelig;tte den ene til at bruge den andens model:</P>
<PRE CLASS="kode-western">  Document datamodel = jTextField1.getDocument();
  jTextField2.setDocument( datamodel );</PRE><H4 CLASS="western">
Eksempel: Et tekstfelt, der kun accepterer store bogstaver</H4>
<P CLASS="western">Ved at lave sin egen datamodel kan man selv
bestemme pr&aelig;cist hvad der kan ske med teksten.</P>
<P CLASS="western">I stedet for at lave en implementation af
Document-interfacet fra grunden (det er ret indviklet) v&aelig;lger
man ofte at arve fra standardmodellen (der hedder <SPAN LANG="da-DK">PlainDocument</SPAN>)
og bare tilsides&aelig;tte den metode, der kaldes for at inds&aelig;tte
tekst i dokumentet:</P>
<PRE CLASS="kode-western">import <SPAN LANG="da-DK">javax.swing.text.</SPAN>*;
public class <SPAN LANG="da-DK">StortDokument</SPAN> extends PlainDocument
{
  public void <B><SPAN LANG="da-DK">insertString</SPAN>(int o, String s, <SPAN LANG="da-DK">AttributeSet</SPAN> a)</B>
    throws <SPAN LANG="da-DK">BadLocationException</SPAN>
  {
    <SPAN STYLE="font-weight: medium"><I>// kald den oprindelige metode med strengen med store bogstaver</I></SPAN>
<B>    <SPAN LANG="da-DK">super.insertString</SPAN>(o, <SPAN LANG="da-DK">s.toUpperCase</SPAN>(), a);</B><SPAN STYLE="font-weight: medium">      </SPAN>
<SPAN STYLE="font-weight: medium">    <I>// log &aelig;ndringen, s&aring; vi kan f&oslash;lge med i hvad der sker</I></SPAN>
    System.out.println(&quot;insertString(&quot;+o+&quot;, '&quot;+s+&quot;') kaldt.\n&quot;);
  }
}</PRE><P CLASS="western">
Ovenst&aring;ende klasse kan bruges som datamodel i et tekstfelt med
koden:</P>
<PRE CLASS="kode-western">  Document datamodel = new StortDokument();
  jTextField2.setDocument( datamodel );</PRE><P CLASS="western">
Af andre klasser, der implementerer Document-interfacet, kan n&aelig;vnes
<SPAN LANG="da-DK">DefaultStyledDocument</SPAN> og <SPAN LANG="da-DK">HTMLDocument.</SPAN>
I disse dokumenttyper har tegnene attributter s&aring;som
skriftst&oslash;rrelse, fed, kursiv, understreget osv. (beregnet til
JEditorPane og <SPAN LANG="da-DK">JTextPane</SPAN>).</P>


<H3 CLASS="western" STYLE="">6.3.2 <a name='afsn6.3.2'></a>Tabeller
(interfacet TableModel)</H3>
<P CLASS="western">Tabeller (JTable) bruger en TableModel som model
og har metoder til at l&aelig;se/s&aelig;tte den:</P>
<PRE CLASS="kode-western">public TableModel <SPAN LANG="da-DK">getModel</SPAN>()
public void <SPAN LANG="da-DK">setModel</SPAN>(TableModel dataModel)</PRE><P CLASS="western">
JTable kalder modellens metoder for at vide, hvad den skal vise. 
</P>
<P CLASS="western">Modellen har interfacet:</P>
<PRE CLASS="ikke-javakode-western">package <SPAN LANG="da-DK">javax.swing.table</SPAN>;

public interface TableModel
{
  public int <SPAN LANG="da-DK">getRowCount</SPAN>();
  public int <SPAN LANG="da-DK">getColumnCount</SPAN>();
  public String <SPAN LANG="da-DK">getColumnName</SPAN>(int <SPAN LANG="da-DK">kollonneindeks</SPAN>);
  public Class <SPAN LANG="da-DK">getColumnClass</SPAN>(int kollonneindeks)
  public boolean <SPAN LANG="da-DK">isCellEditable</SPAN>(int r&aelig;kkeindeks, int kollonneindeks);
  public Object <SPAN LANG="da-DK">getValueAt</SPAN>(int r&aelig;kkeindeks, int kollonneindeks);
  public void <SPAN LANG="da-DK">setValueAt</SPAN>(Object v&aelig;rdi, int r&aelig;kkeindeks, int kollonneindeks);
  public void <SPAN LANG="da-DK">addTableModelListener</SPAN>(<SPAN LANG="da-DK">TableModelListener</SPAN> lytter);
  public void <SPAN LANG="da-DK">removeTableModelListener</SPAN>(TableModelListener lytter);
}</PRE><P CLASS="western">
En m&aring;de at lave en tabel p&aring; er alts&aring; at lave en
klasse, der implementerer TableModel-interfacet, og s&aring; bruge
den som datamodel. Det er dog lidt besv&aelig;rligt, fordi man selv
skal holde styr p&aring; lyttere og implementere
addTableModelListener() og removeTableModelListener().</P>
<P CLASS="western">Man kan ogs&aring; v&aelig;lge at arve fra
<SPAN LANG="da-DK">AbstractTableModel</SPAN> (eller
<SPAN LANG="da-DK">DefaultTableModel</SPAN>), der implementerer
TableModel og selv s&oslash;rger for at h&aring;ndtere lyttere.</P>
<P CLASS="western">Her er en klasse, der f&aring;r et<SPAN LANG="da-DK">
endimensionalt </SPAN>array af strenge til at fungere som en
TableModel, s&aring; den kan vises af JTable (s&aring;dan en
hj&aelig;lpeklasse, der f&aring;r 'noget til at passe ind i noget',
kaldes en adapter, se <a href='kapitel17.jsp#afsn17.2'>afsnit 17.2</a>). 
</P>
<P CLASS="western">Tabellen kommer til at vise to kolonner, f&oslash;rste
kolonne med r&aelig;kkenummeret og anden kolonne er indholdet af
arrayet p&aring; det p&aring;g&aelig;ldende r&aelig;kkenummer.</P>
<PRE CLASS="kode-western">import javax.swing.table.*;

public class <SPAN LANG="da-DK">StrengArrayTableModel</SPAN> extends AbstractTableModel
{
  private String[] data;
  public  StrengArrayTableModel(String[] dat) { data = dat; }

  public int getColumnCount()    { return 2; }
  public int getRowCount()       { return <SPAN LANG="da-DK">data.length</SPAN> ;}
  public Object getValueAt(int r&aelig;k, int kol)
  {
    if (kol == 0) return new Integer(r&aelig;k); <I>// f&oslash;rste kolonne er indeks</I>
    else return data[r&aelig;k];                 <I>// anden kolonne er strengenes v&aelig;rdi</I>
  }
}</PRE><P CLASS="western">
Her er et lille program, der benytter adapteren til at vise et array
af strenge:</P>
<PRE CLASS="kode-western">i<IMG SRC="bog7_html_mcd52a74.png" NAME="Graphic7" ALIGN=RIGHT HSPACE=4 BORDER=0>mport javax.swing.*;

public class <SPAN LANG="da-DK">BenytStrengArrayTableModel</SPAN>
{
  public static void main(String[] args)
  {
    JFrame f = new JFrame();
    JTable t;
    <SPAN LANG="da-DK">f.setSize</SPAN>(200, 200);

    String[] <B><SPAN LANG="da-DK">arr</SPAN> = {&quot;a&quot;,&quot;b&quot;,&quot;hej&quot;,&quot;c&quot;}</B>; <I>// strenge</I>
    t = new JTable(<B>new StrengArrayTableModel(arr)</B>);

    <SPAN LANG="da-DK">f.getContentPane</SPAN>().add(t);
    <SPAN LANG="da-DK">f.setVisible</SPAN>(true);
  }
}</PRE><P CLASS="western">
Man kan naturligvis ogs&aring; bare <I>lade</I>, som om man viser
nogle data uden at hente dem fra nogen datastruktur. Eksempelvis er
her en datamodel, der repr&aelig;senterer den lille tabel. Den har 10
r&aelig;kker og 10 kolonner, og hver celle har samme v&aelig;rdi som
r&aelig;kkenummer+1 gange <SPAN LANG="da-DK">kolonnenummer</SPAN>+1.</P>
<PRE CLASS="kode-western">import javax.swing.table.*;

public class <SPAN LANG="da-DK">DenLilleTabel</SPAN> extends AbstractTableModel 
{
  public int getColumnCount()    { return 10; }
  public int getRowCount()       { return 10;}
  public Object getValueAt(int r, int k) { return new Integer((r+1)*(k+1)); }
}</PRE><P CLASS="western">
Vist i en JTable giver klassen f&oslash;lgende data:</P>
<P CLASS="western" ALIGN=CENTER><IMG SRC="bog7_html_3306bee9.png" NAME="Graphic6" ALIGN=BOTTOM BORDER=0></P>
<P CLASS="western">En anden m&aring;de er at angive et todimensionalt
array (eller en Vector af Vector-objekter) med startv&aelig;rdier i
konstrukt&oslash;ren til JTable. Da vil den selv oprette en
datamodel, der repr&aelig;senterer data.</P>
<H3 CLASS="western">6.3.3 <a name='afsn6.3.3'></a>Knapper (interfacet ButtonModel)</H3>
<P CLASS="western">Alle knapper og lignende, dvs. JButton,
<SPAN LANG="da-DK">JToggleButton</SPAN>, <SPAN LANG="da-DK">JMenuItem</SPAN>,
<SPAN LANG="da-DK">JMenu</SPAN>, <SPAN LANG="da-DK">JCheckbox</SPAN>
og <SPAN LANG="da-DK">JRadiobox</SPAN> bruger en ButtonModel som
datamodel.</P>
<P CLASS="western">Modellen l&aelig;ses og s&aelig;ttes med
metoderne:</P>
<PRE CLASS="kode-western">ButtonModel getModel()
void setModel(ButtonModel nyModel)</PRE>
<P CLASS="western">Selve ButtonModel er et interface med metoderne</P>
<PRE CLASS="ikke-javakode-western">public interface ButtonModel extends <SPAN LANG="da-DK">ItemSelectable</SPAN>
{
  public void <SPAN LANG="da-DK">setArmed</SPAN>(boolean b);
  public void <SPAN LANG="da-DK">setSelected</SPAN>(boolean b);
  public void <SPAN LANG="da-DK">setEnabled</SPAN>(boolean b);
  public void <SPAN LANG="da-DK">setPressed</SPAN>(boolean b);
  public void <SPAN LANG="da-DK">setRollover</SPAN>(boolean b);
  public void <SPAN LANG="da-DK">setMnemonic</SPAN>(int key);
  public int  <SPAN LANG="da-DK">getMnemonic</SPAN>();
  public void <SPAN LANG="da-DK">setActionCommand</SPAN>(String s);
  public String <SPAN LANG="da-DK">getActionCommand</SPAN>();
  public void <SPAN LANG="da-DK">setGroup</SPAN>(<SPAN LANG="da-DK">ButtonGroup</SPAN> group);

<I>  // ... flere metoder</I>
}</PRE>
<H3 CLASS="western">6.3.4 <a name='afsn6.3.4'></a>Andre komponenter</H3>
<P CLASS="western">I de fleste andre hedder metoderne til at
afl&aelig;se/udskifte datamodellen hhv. getModel() og setModel(). 
</P>
<P CLASS="western">JComboBox bruger modellen <SPAN LANG="da-DK">ComboBoxModel</SPAN>:</P>
<PRE CLASS="kode-western">void setModel(ComboBoxModel nyModel)
ComboBoxModel getModel()</PRE>
<P CLASS="western">JList bruger modellen <SPAN LANG="da-DK">ListModel</SPAN>:</P>
<PRE CLASS="kode-western">public ListModel getModel()
public void setModel(ListModel nyModel)</PRE>
<P CLASS="western"><SPAN LANG="da-DK">JProgressBar</SPAN>, <SPAN LANG="da-DK">JScrollBar</SPAN>
og <SPAN LANG="da-DK">JSlider</SPAN>, dvs. komponenter, der p&aring;
en eller anden m&aring;de grafisk skal vise en v&aelig;rdi i et
interval, bruger modellen <SPAN LANG="da-DK">BoundedRangeModel</SPAN>:</P>
<PRE CLASS="kode-western">public BoundedRangeModel getModel()
public void setModel(BoundedRangeModel nyModel)</PRE>
<P CLASS="western">JTree bruger modellen <SPAN LANG="da-DK">TreeModel</SPAN>:</P>
<PRE CLASS="kode-western">public TreeModel getModel()
public void setModel(TreeModel nyModel)</PRE>
<P CLASS="western">... og s&aring; videre. 
</P>
<P CLASS="western">Enhver Swing-komponent har alts&aring; en
datamodel, der beskriver komponentens tilstand.</P>

<H3 CLASS="western">6.3.5 <a name='afsn6.3.5'></a>Opgaver</H3>
<OL>
  <LI><P CLASS="western">Lav et program med med to tekstfelter, der
  deler samme dokument.</P>
  <LI><P CLASS="western">Tilf&oslash;j et tekstfelt, der kun
  accepterer store bogstaver til programmet.</P>
  <LI><P CLASS="western">Pr&oslash;v at lade to knapper dele
  datamodel. Hvad sker der s&aring;? Hvad med en menuindgang og en
  knap? 
  </P>
</OL>

<H3 CLASS="western" STYLE="">6.3.6 <a name='afsn6.3.6'></a>L&oslash;sning</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/kapitel6.jsp#afsn6.3.6">
  <input type='checkbox' name='vis' value='6.3.6'>Jeg erklærer, at jeg allerede har købt bogen<br />
  <input type='checkbox' name='vis' value='6.3.6'>Jeg lover at anskaffe den i nær fremtid.<br />
  <input type='submit' value='Vis mig dette afsnit'>
  </form>

	  <H2 CLASS="western" STYLE="">6.4 <a name='afsn6.4'></a>Pr&aelig;sentationsdelen
i Swing</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/kapitel6.jsp#afsn6.4">
  <input type='checkbox' name='vis' value='6.4'>Jeg erklærer, at jeg allerede har købt bogen<br />
  <input type='checkbox' name='vis' value='6.4'>Jeg lover at anskaffe den i nær fremtid.<br />
  <input type='submit' value='Vis mig dette afsnit'>
  </form>

	  
<H3 CLASS="western">6.4.1 <a name='afsn6.4.1'></a>Lister (ListCellRenderer)</H3>
<P CLASS="western">For JComboBox og JList skal fremviser-objektet
implementere ListCellRenderer:</P>
<PRE CLASS="ikke-javakode-western">package javax.swing;

public interface ListCellRenderer
{
  /**
<I>   * Return a component that has been configured to display the specified</I>
<I>   * value. That component's &lt;code&gt;paint&lt;/code&gt; method is then called to</I>
<I>   * &quot;render&quot; the cell.  If it is necessary to compute the dimensions</I>
<I>   * of a list because the list cells do not have a fixed size, this method</I>
<I>   * is called to generate a component on which &lt;code&gt;getPreferredSize&lt;/code&gt;</I>
<I>   * can be invoked.</I>
<I>   *</I>
<I>   * @param list The JList we're painting.</I>
<I>   * @param value The value returned by <SPAN LANG="da-DK">list.getModel</SPAN>()<SPAN LANG="da-DK">.getElementAt</SPAN>(index).</I>
<I>   * @param index The cells index.</I>
<I>   * @param <SPAN LANG="da-DK">isSelected</SPAN> True if the specified cell was selected.</I>
<I>   * @param <SPAN LANG="da-DK">cellHasFocus</SPAN> True if the specified cell has the focus.</I>
<I>   * @return A component whose paint() method will render the specified value.</I>
<I>   *</I>
<I>   * @see JList</I>
<I>   * @see <SPAN LANG="da-DK">ListSelectionModel</SPAN></I>
<I>   * @see ListModel</I>
<I>   */</I>
  Component <SPAN LANG="da-DK">getListCellRendererComponent</SPAN>(
    JList list,
    Object value, int index,
    boolean isSelected, boolean cellHasFocus);
}</PRE><P CLASS="western">
Fremvisningen s&aelig;ttes med metoden
<SPAN LANG="da-DK">setCellRenderer</SPAN>(ListCellRenderer
<SPAN LANG="da-DK">cellRenderer</SPAN>).</P>
<P CLASS="western">Har man ikke angivet nogen fremviser, bruges
klassen DefaultListCellRenderer, der kan vise ikoner (Icon) og
tekster. Vil man lave sin egen fremvisning, anbefales det, at man
arver fra denne og omdefinerer getListCellRendererComponent() eller
paint().</P>
<H4 CLASS="western">Eksempel p&aring; pr&aelig;sentationsdel af en
liste</H4>
<P CLASS="western">Her er et eksempel p&aring; en liste, der viser
alle sine punkter overstreget. Det er gjort ved at arve fra 
DefaultListCellRenderer og omdefinere paint()-metoden til at tegne en
skr&aring; streg.</P>
<PRE CLASS="kode-western">import java.awt.*;
import javax.swing.*;
public class <SPAN LANG="da-DK">OverstregedeCeller</SPAN> extends DefaultListCellRenderer {
  public void paint(Graphics g) {
    super.paint(g);                          <I>// tegn cellen</I>
    g.drawLine(0,0,getWidth(),getHeight());  <I>// tegn en streg<SPAN LANG="da-DK"> hen over </SPAN>den</I>
  }
}</PRE><H3 CLASS="western">
6.4.2 <a name='afsn6.4.2'></a>Eksempel: Pr&aelig;sentation af skrifter i en liste</H3>
<P CLASS="western">Det f&oslash;lgende eksempel p&aring; en
pr&aelig;sentationsdel til lister (ListCellRenderer) viser en liste
over skrifttyper, hvor hver skrifttype bliver vist som den rent
faktisk ser ud p&aring; sk&aelig;rmen:</P>
<P CLASS="western" ALIGN=CENTER><IMG SRC="bog7_html_m63cc94b2.png" NAME="Grafik34" ALIGN=BOTTOM BORDER=0></P>
<P CLASS="western">Fremvisningen sker ved at arve fra
DefaultListCellRenderer og tilsides&aelig;tte metoden            
getListCellRendererComponent():</P>
<PRE CLASS="kode-western">import java.awt.*;
import java.util.*;
import javax.swing.*;

public class Skriftfremviser extends DefaultListCellRenderer
{
  Map skrifter = new HashMap(); <I>// afbildning fra skriftnavn til Font-objekt</I>

  public Component getListCellRendererComponent(
    JList liste,
    Object v&aelig;rdi, int index,
    boolean valgt, boolean harFokus)
  {
    Component visningsKomponent =
      super.getListCellRendererComponent(liste, v&aelig;rdi, index, valgt, harFokus);

    System.out.println(index +&quot; &quot;+ v&aelig;rdi); <I>// se hvor ofte metoden bliver kaldt</I>

    if (v&aelig;rdi != null)
    {
      Font skrifttype = (Font) skrifter.get(v&aelig;rdi);
      if (skrifttype==null) 
      {
        skrifttype = new Font( (String) v&aelig;rdi, Font.PLAIN, 14); <I>// indl&aelig;s skrift</I>
        skrifter.put(v&aelig;rdi, skrifttype);                        <I>// ..og husk den</I>
      }
      visningsKomponent.setFont(skrifttype);
    }

    return visningsKomponent;
  }
}</PRE><P CLASS="western">
I getListCellRendererComponent() kalder vi f&oslash;rst superklassens
oprindelige metode for at f&aring; ordnet andre ting, s&aring;som at
afg&oslash;re hvilken tekst, der skal vises og om cellen (indgangen)
skal have en speciel farve, fordi den er valgt/har fokus.</P>
<P CLASS="western">Derefter pr&oslash;ver vi at indl&aelig;se den
p&aring;g&aelig;ldende skrifttype. For at undg&aring; at oprette alt
for mange Font-objekter laver vi en afbildning fra skriftnavne til
Font-objekter og <SPAN LANG="da-DK">cacher</SPAN> Font-objekterne.</P>
<P CLASS="western" ALIGN=CENTER><IMG SRC="bog7_html_2eec6c3.png" NAME="Grafik36" ALIGN=BOTTOM BORDER=0></P>

<P CLASS="western">Her er et program, der benytter Skriftfremviser. 
</P>
<PRE CLASS="kode-western">import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class <SPAN LANG="da-DK">BenytSkriftfremviser</SPAN> extends JFrame implements ActionListener
{
  JComboBox jComboBox1 = new JComboBox();
  JTextArea jTextArea1 = new JTextArea();

  public BenytSkriftfremviser() {
    <SPAN LANG="da-DK">setTitle</SPAN>(&quot;BenytSkriftfremviser&quot;);

    String[] skriftnavne = <SPAN LANG="da-DK">GraphicsEnvironment.</SPAN>
      <SPAN LANG="da-DK">getLocalGraphicsEnvironment</SPAN>()<SPAN LANG="da-DK">.getAvailableFontFamilyNames</SPAN>();

    jTextArea1.setLineWrap(true);
    jTextArea1.setText(&quot;En snegl p&aring; vejen er tegn p&aring; regn\ni Spanien\n\n&quot;
      +&quot;Hvorn&aring;r smager en Tuborg bedst?\<SPAN LANG="da-DK">nHvergang</SPAN>!&quot;);

    jComboBox1.setModel(new <SPAN LANG="da-DK">DefaultComboBoxModel</SPAN>(skriftnavne));
    jComboBox1.setRenderer(new Skriftfremviser());
    jComboBox1.addActionListener(this);

    JPanel jPanel1 = new JPanel();
    jPanel1.setLayout(new BorderLayout());
    jPanel1.add(jComboBox1, <SPAN LANG="da-DK">BorderLayout.EAST</SPAN>);

    <SPAN LANG="da-DK">getContentPane</SPAN>().setLayout(new BorderLayout());
    getContentPane().add(jPanel1, BorderLayout.NORTH);
    getContentPane().add(jTextArea1, BorderLayout.CENTER);
  }

  public void actionPerformed(ActionEvent e) { <I>// kaldes n&aring;r valglisten &aelig;ndres</I>
    String skriftnavn = (String) jComboBox1.getSelectedItem();
    System.out.println(skriftnavn + &quot; &quot; + e);
    jTextArea1.setFont( new Font( skriftnavn, Font.PLAIN, 20) );
  }

  public static void main(String[] args) {
    BenytSkriftfremviser vindue = new BenytSkriftfremviser();
    vindue.pack();
    vindue.setVisible(true);
  }
}</PRE>

<H3 CLASS="western" STYLE="">6.4.3 <a name='afsn6.4.3'></a>Tabeller
(TableCellRenderer)</H3>
<P CLASS="western">For JTable kan man s&aelig;tte fremvisningen p&aring;
hver kolonne (hentet med <SPAN LANG="da-DK">getColumn</SPAN>() og
navnet p&aring; kolonnen) med metoden: <SPAN LANG="da-DK">setRenderer</SPAN>(TableCellRenderer
fremviser).</P>
<PRE CLASS="ikke-javakode-western">package javax.swing.table;

public interface TableCellRenderer
{ 
<I>  /**</I>
<I>   *  Returns the component used for drawing the cell.  This method is</I>
<I>   *  used to configure the renderer appropriately before drawing.</I>
<I>   *</I>
<I>   * @param table     the &lt;code&gt;JTable&lt;/code&gt; that is asking the</I>
<I>   *          renderer to draw; can be &lt;code&gt;null&lt;/code&gt;</I>
<I>   * @param value     the value of the cell to be rendered.  It is</I>
<I>   *          up to the specific renderer to interpret</I>
<I>   *          and draw the value.  For example, if</I>
<I>   *          &lt;code&gt;value&lt;/code&gt;</I>
<I>   *          is the string &quot;true&quot;, it could be rendered as a</I>
<I>   *          string or it could be rendered as a check</I>
<I>   *          box that is checked.  &lt;code&gt;null&lt;/code&gt; is a</I>
<I>   *          valid value</I>
<I>   * @param isSelected  true if the cell is to be rendered with the</I>
<I>   *          selection highlighted; otherwise false</I>
<I>   * @param <SPAN LANG="da-DK">hasFocus</SPAN>    if true, render cell appropriately.  For</I>
<I>   *          example, put a special border on the cell, if</I>
<I>   *          the cell can be edited, render in the color used</I>
<I>   *          to indicate editing</I>
<I>   * @param row     the row index of the cell being drawn.  When</I>
<I>   *          drawing the header, the value of</I>
<I>   *          &lt;code&gt;row&lt;/code&gt; is -1</I>
<I>   * @param column    the column index of the cell being drawn</I>
<I>   */</I>

  Component <SPAN LANG="da-DK">getTableCellRendererComponent</SPAN>(
    JTable table,
    Object value,
    boolean isSelected, boolean hasFocus,
    int row, int column);
}</PRE>
<P CLASS="western">Her er et eksempel p&aring; et pr&aelig;sentationsobjekt
oprettet direkte ud fra interfacet. Det er beregnet til at vise
Color-objekter. I getTableCellRendererComponent() konfigureres en
JLabel derfor til at vise den p&aring;g&aelig;ldende farve, hvorefter
denne JLabel returneres:</P>
<PRE CLASS="kode-western">import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;

public class <SPAN LANG="da-DK">Farvepraesentation</SPAN> implements TableCellRenderer
{
  JLabel <SPAN LANG="da-DK">jLabel</SPAN> = new JLabel();          <I>// genbrug den samme komponent</I>

  public Component getTableCellRendererComponent(JTable tabel, Object v&aelig;rdi,
          boolean <SPAN LANG="da-DK">erValgt</SPAN>, boolean harFokus, int r&aelig;kke, int kolonne)
  {
    if (v&aelig;rdi <SPAN LANG="da-DK">instanceof</SPAN> Color)          <I>// er v&aelig;rdien af type Double?</I>
    {
      Color f = (Color) v&aelig;rdi;
      <SPAN LANG="da-DK">jLabel.setBackground</SPAN>(f);           <I>// hele baggrunden viser farven</I>
      <SPAN LANG="da-DK">jLabel.setForeground</SPAN>(<SPAN LANG="da-DK">f.darker</SPAN>());  <I>// tekstfarven er lidt m&oslash;rkere</I>
      <SPAN LANG="da-DK">jLabel.setOpaque</SPAN>(true);            <I>// uigennemsigtig s&aring; baggrunden kan ses</I>
      <SPAN LANG="da-DK">jLabel.setText</SPAN>(&quot;farve&quot;);           <I>// vis bare en eller anden tekst</I>
    } else {
      jLabel.setBackground(Color.white); <I>// er objektet ikke en farve, s&aring; vis</I>
      jLabel.setForeground(<SPAN LANG="da-DK">Color.black</SPAN>); <I>// det som toString() giver</I>
      jLabel.setText(<SPAN LANG="da-DK">v&aelig;rdi.toString</SPAN>());
    }
    return jLabel;                       <I>// return&eacute;r komponenten der skal vises</I>
  }
}</PRE>
<P CLASS="western">I stedet for at implementere TableCellRenderer
direkte tilr&aring;des det dog, at man arver fra klassen
DefaultTableCellRenderer og definerer metoden setValue(). Det
f&oslash;lgende eksempel pr&aelig;senterer tal (af typen Double) med
sort skrift, hvis de er positive, og r&oslash;d skrift, hvis de er
negative:</P>
<PRE CLASS="kode-western">import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;

public class <SPAN LANG="da-DK">Talpraesentation</SPAN> extends DefaultTableCellRenderer
{
  public void setValue(Object v&aelig;rdi)
  {
    if (v&aelig;rdi instanceof Double) {
      if (((Double) v&aelig;rdi)<SPAN LANG="da-DK">.doubleValue</SPAN>()&lt;0) <SPAN LANG="da-DK">setForeground</SPAN>(Color.red);
      else setForeground(<SPAN LANG="da-DK">Color.blue</SPAN>);
    }
    else setForeground(Color.black);

    setText(v&aelig;rdi.toString());
  }
}</PRE><P CLASS="western">
Som det ses, er det alts&aring; simplere at arve fra
DefaultTableCellRenderer (som implementerer TableCellRenderer).
Samtidigt er DefaultTableCellRenderer optimeret beregnet p&aring; den
ret specielle brug, som JTable g&oslash;r af den, s&aring; det giver
ogs&aring; mere effektiv kode.</P>
<P CLASS="western">Begge klasser kan ses brugt i <a href='kapitel6.jsp#afsn6.6.2'>afsnit 6.6.2</a>.</P>

<H3 CLASS="western">6.4.4 <a name='afsn6.4.4'></a>Tr&aelig;er (TreeCellRenderer)</H3>
<P CLASS="western">Tilsvarende har JTree metoden
setCellRenderer(TreeCellRenderer fremviser) og en
DefaultTreeCellRenderer, der bruges, hvis en anden fremviser ikke
specificeres.</P>

<H3 CLASS="western">6.4.5 <a name='afsn6.4.5'></a>Opgaver</H3>
<OL>
  <LI><P CLASS="western">Pr&oslash;v Skriftfremviser-eksemplet.</P>
  <LI><P CLASS="western">Lav din egen Farvefremviser, der giver
  brugeren mulighed for at v&aelig;lge mellem et antal farver.</P>
</OL>

<H2 CLASS="western" STYLE="">6.5 <a name='afsn6.5'></a>Kontroldelen
af Swing-komponenter</SPAN></H2>
<P CLASS="western">P&aring; tilsvarende m&aring;de som med Renderer
findes der (for tabeller og tr&aelig;er) ogs&aring; klasser og
metoder til at specificere, hvordan redigering af indholdet af
komponenten skal ske .</P>
<P CLASS="western">M&aring;den at arbejde med disse svarer ret meget
til m&aring;den at arbejde med pr&aelig;sentations-delen.
Kontrol-delene skal implementere interfacet <SPAN LANG="da-DK">CellEditor</SPAN>:</P>
<PRE CLASS="ikke-javakode-western">public interface CellEditor {
  public Object <SPAN LANG="da-DK">getCellEditorValue</SPAN>();
  public boolean isCellEditable(<SPAN LANG="da-DK">EventObject</SPAN> <SPAN LANG="da-DK">anEvent</SPAN>);
  public boolean <SPAN LANG="da-DK">shouldSelectCell</SPAN>(EventObject anEvent);
  public boolean <SPAN LANG="da-DK">stopCellEditing</SPAN>();
  public void <SPAN LANG="da-DK">cancelCellEditing</SPAN>();
  public void <SPAN LANG="da-DK">addCellEditorListener</SPAN>(<SPAN LANG="da-DK">CellEditorListener</SPAN> l);
  public void <SPAN LANG="da-DK">removeCellEditorListener</SPAN>(CellEditorListener l);
}</PRE><P CLASS="western">
I stedet for at skrive sin egen editor anbefales det at anvende
(eller eventuelt arve fra) klassen <SPAN LANG="da-DK">DefaultCellEditor</SPAN>
(beskrevet nedenfor). 
</P>
<P CLASS="western">Det er der eksempler p&aring; i <a href='kapitel6.jsp#afsn6.6.2'>afsnit 6.6.2</a>.</P>
<H3 CLASS="western">6.5.1 <a name='afsn6.5.1'></a>Tabeller (TableCellEditor)</H3>
<P CLASS="western">Interfacet TableCellEditor (der udvider
CellEditor) skal implementeres hvis man selv vil bestemme hvordan
redigeringen af en tabel skal foreg&aring;. Det har metoden:</P>
<PRE CLASS="kode-western">  Component <SPAN LANG="da-DK">getTableCellEditorComponent</SPAN>(
    JTable table, 
    Object value,
    boolean isSelected,
    int row, 
    int column
  );</PRE><P CLASS="western">
som skal defineres til at returnere en (korrekt konfigureret)
komponent, der st&aring;r for redigeringen af den p&aring;g&aelig;ldende
celle. 
</P>
<H3 CLASS="western">6.5.2 <a name='afsn6.5.2'></a>Tr&aelig;er (TreeCellEditor)</H3>
<P CLASS="western">Interfacet TreeCellEditor (der udvider CellEditor)
skal implementeres hvis man selv vil bestemme, hvordan redigeringen
af et tr&aelig; skal foreg&aring;. Det har metoden:</P>
<PRE CLASS="kode-western">  Component <SPAN LANG="da-DK">getTreeCellEditorComponent</SPAN>(
    JTree tree, 
    Object value,
    boolean isSelected,
    boolean expanded,
    boolean leaf, 
    int row
  );</PRE><P CLASS="western">
som skal defineres til at returnere en (korrekt konfigureret)
komponent, der st&aring;r for redigeringen af den p&aring;g&aelig;ldende
gren af tr&aelig;et.</P>
<H3 CLASS="western">6.5.3 <a name='afsn6.5.3'></a>Standardredigering med DefaultCellEditor</H3>
<P CLASS="western">DefaultCellEditor implementerer b&aring;de
TableCellEditor og TreeCellEditor. Den bruges af b&aring;de JTable og
JTree, hvis ingen anden editor er angivet. I dens konstrukt&oslash;r
kan man angive en JTextField, JCheckBox eller JComboBox, som da vil
blive brugt til redigeringen.</P>

<H2 CLASS="western" STYLE="">6.6 <a name='afsn6.6'></a>Eksempler</SPAN></H2>
<P CLASS="western">Sammen med JDK'en f&oslash;lger der en r&aelig;kke
eksempler (ligger i f.eks. jdk1.4/demo/). Det er en virkelig god id&eacute;
at pr&oslash;ve nogle af disse eksempler, da de illustrerer de
muligheder, man har som programm&oslash;r, og samtidig f&oslash;lger
kildeteksten med til alle eksemplerne, s&aring; man kan se, hvordan
det er programmeret.</P>
<H3 CLASS="western">6.6.1 <a name='afsn6.6.1'></a>SwingSet2-demo af JTable</H3>
<P CLASS="western">Et eksempel, der illustrerer de fleste af
mulighederne med Swing-komponenter, hedder SwingSet2. Det ligger i
jdk1.4/demo/jfc/SwingSet2 og startes ved at dobbeltklikke p&aring;
jar-filen eller fra kommandolinjen skrive: java -jar  SwingSet2.jar. 
</P>
<P CLASS="western">Herunder ses sk&aelig;rmbilledet af SwingSet2's
demo af JTable:</P>
<P CLASS="western" ALIGN=CENTER><IMG SRC="bog7_html_m187fd2b9.png" NAME="Grafik5" ALIGN=BOTTOM BORDER=0></P>
<P CLASS="western">Der er lavet kontroller til de fleste ting, kan
&quot;dreje p&aring;&quot; for en JTable, bl.a.:</P>
<PRE CLASS="kode-western"><I>// kan brugeren bytte om p&aring; r&aelig;kkef&oslash;lgen kolonnerne vises i ved at tr&aelig;kke i dem</I>
<SPAN LANG="da-DK">jTable.getTableHeader</SPAN>()<SPAN LANG="da-DK">.setReorderingAllowed</SPAN>(flag);

<I>// skal der vises vandrette/lodrette linjer mellem cellerne</I>
<SPAN LANG="da-DK">jTable.setShowHorizontalLines</SPAN>(flag);    <SPAN LANG="da-DK">jTable.setShowVerticalLines</SPAN>(flag);

<I>// afstand mellem cellerne</I>
<SPAN LANG="da-DK">jTable.setIntercellSpacing</SPAN>(new Dimension(bredde, h&oslash;jde));

<I>// skal der v&aelig;lges hele kolonner/r&aelig;kker n&aring;r brugeren klikker i en celle</I>
<SPAN LANG="da-DK">jTable.setColumnSelectionAllowed</SPAN>(flag); <SPAN LANG="da-DK">jTable.setRowSelectionAllowed</SPAN>(flag);

<I>// r&aelig;kkeh&oslash;jden </I>
<SPAN LANG="da-DK">jTable.setRowHeight</SPAN>(height);</PRE><P CLASS="western">
Kildeteksten til SwingSet2 er lidt sv&aelig;r at overskue, da den
samtidig demonstrerer internationalisering (programmet kan ogs&aring;
vises p&aring; kinesisk!), tastaturgenveje og en masse andet.</P>
<H3 CLASS="western">6.6.2 <a name='afsn6.6.2'></a>Eksempel med JTable</H3>
<P CLASS="western">Herunder ses et simplere eksempel p&aring; brug af
JTable (inspireret af SwingSet2).</P>
<P CLASS="western"><IMG SRC="bog7_html_58342826.png" NAME="Grafik6" ALIGN=BOTTOM BORDER=0></P>

<PRE CLASS="kode-western">import java.awt.*;
import javax.swing.*;
import <SPAN LANG="da-DK">javax.swing.event.</SPAN>*;
import javax.swing.table.*;

public class <SPAN LANG="da-DK">BenytJTable</SPAN> extends JFrame {
  JTable jTable1 = new JTable();
  <SPAN LANG="da-DK">JScrollPane</SPAN> jScrollPane1 = new JScrollPane();

  public static void main(String[] args)  {
    BenytJTable vindue = new BenytJTable(); <I>// opret vinduet</I>
    vindue.pack();                          <I>// tilpas st&oslash;rrelsen til indholdet</I>
    vindue.setVisible(true);                <I>// vis vinduet</I>
  }

  private void jbInit() throws Exception {
    this.getContentPane().add(jScrollPane1, BorderLayout.CENTER);
    jScrollPane1.getViewport().add(jTable1, null);
  }

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

<I>    // Hj&aelig;lpevariabler</I>
    <SPAN LANG="da-DK">ImageIcon</SPAN> &aelig;ble     = new ImageIcon(&quot;<SPAN LANG="da-DK">apple.jpg</SPAN>&quot;,     &quot;&aelig;ble&quot;);
    ImageIcon asparges = new ImageIcon(&quot;<SPAN LANG="da-DK">asparagus.jpg</SPAN>&quot;, &quot;asparges&quot;);
    ImageIcon banan    = new ImageIcon(&quot;<SPAN LANG="da-DK">banana.jpg</SPAN>&quot;,    &quot;banan&quot;);
    ImageIcon broccoli = new ImageIcon(&quot;<SPAN LANG="da-DK">broccoli.jpg</SPAN>&quot;,  &quot;broccoli&quot;);
    ImageIcon gulerod  = new ImageIcon(&quot;<SPAN LANG="da-DK">carrot.jpg</SPAN>&quot;,    &quot;gulerod&quot;);
    ImageIcon kiwi     = new ImageIcon(&quot;<SPAN LANG="da-DK">kiwi.jpg</SPAN>&quot;,      &quot;kiwi&quot;);
    ImageIcon l&oslash;g      = new ImageIcon(&quot;<SPAN LANG="da-DK">onion.jpg</SPAN>&quot;,     &quot;l&oslash;g&quot;);
    Boolean ja  = <SPAN LANG="da-DK">Boolean.TRUE</SPAN>;
    Boolean nej = <SPAN LANG="da-DK">Boolean.FALSE</SPAN>;

<I>    /////////////////////////////////////////////////</I>
<I>    // Data</I>
<I>    /////////////////////////////////////////////////</I>
    final String[] kolonner =
      {&quot;Navn&quot;,   &quot;Yndlingsfarve&quot;, &quot;Yndlingstal&quot;,&quot;Yndlingsret&quot;,&quot;Enlig?&quot;,&quot;Sexet?&quot;};

    final Object[][] data = {
      {&quot;Hans Petersen&quot;,   Color.blue,     new Double(44),   &aelig;ble,    ja,  nej},
      {&quot;Jacob <SPAN LANG="da-DK">S&oslash;rensenn</SPAN>&quot;, <SPAN LANG="da-DK">Color.yellow</SPAN>,   new Double(42),   kiwi,    ja,  ja},
      {&quot;Grethe Ibsen&quot;,    Color.blue,     new Double(-37),  l&oslash;g,     nej, nej},
      {&quot;Kurt Ibsen&quot;,      <SPAN LANG="da-DK">Color.darkGray</SPAN>, new Double(1),    banan,   nej, nej},
      {&quot;Karin Ibsen&quot;,     Color.green,    new Double(10.5), gulerod, nej, ja}
    };

    jTable1.setRowHeight(2*<SPAN LANG="da-DK">&aelig;ble.getIconHeight</SPAN>()/3); <I>// s&aelig;t h&oslash;jden af cellerne</I>

<I>    /////////////////////////////////////////////////</I>
<I>    // <B>Oprettelse af datamodellen</B></I>
<I>    /////////////////////////////////////////////////</I>

<I>    /* Man kan oprette en datamodel direkte ud fra <SPAN LANG="da-DK">interfacet...</SPAN></I>
<I>    class <SPAN LANG="da-DK">DatamodelFraInterface</SPAN> implements TableModel</I>
<I>    {</I>
<I>      public int getColumnCount()              { return <SPAN LANG="da-DK">kolonner.length</SPAN>; }</I>
<I>      public int getRowCount()                 { return data.length; }</I>
<I>      public Object getValueAt(int r, int k)   { return data[r][k]; }</I>
<I>      public String getColumnName(int k)       { return kolonner[k]; }</I>
<I>      public Class getColumnClass(int k)       { return data[0][k]<SPAN LANG="da-DK">.getClass();}</SPAN></I>
<SPAN LANG="da-DK"><I>      public boolean isCellEditable(int r, int k)    { return k != 1; }</I></SPAN>
<SPAN LANG="da-DK"><I>      public void setValueAt(Object v, int r, int k) { data[r][k]=v; }</I></SPAN>
<SPAN LANG="da-DK"><I>      public void addTableModelListener(TableModelListener p0) {}    // hmm...</I></SPAN>
<SPAN LANG="da-DK"><I>      public void removeTableModelListener(TableModelListener p0) {} // hmm...</I></SPAN>
<SPAN LANG="da-DK"><I>    };</I></SPAN>
<SPAN LANG="da-DK"><I>    jTable1.setModel(new DatamodelFraInterface());</I></SPAN>
<SPAN LANG="da-DK"><I>    */</I></SPAN>

<SPAN LANG="da-DK"><I>    // eller oprette fra en hj&aelig;lpeklasse der s&oslash;rger for bl.a. h&aelig;ndelser</I></SPAN>
<SPAN LANG="da-DK">    class DatamodelFraHjaelpeklasse extends AbstractTableModel</SPAN>
<SPAN LANG="da-DK">    {</SPAN>
<SPAN LANG="da-DK">      public int getColumnCount()               { return kolonner.length; }</SPAN>
<SPAN LANG="da-DK">      public int getRowCount()                  { return data.length; }</SPAN>
<SPAN LANG="da-DK">      public Object getValueAt(int r, int k)    { return data[r][k]; }</SPAN>
<SPAN LANG="da-DK">      public String getColumnName(int k)        { return kolonner[k]; }</SPAN>
<SPAN LANG="da-DK">      public Class getColumnClass(int k)        { return data[0][k].getClass();}</SPAN>
<SPAN LANG="da-DK">      public boolean isCellEditable(int r, int k)   { return k != 1; }</SPAN>
<SPAN LANG="da-DK">      public void setValueAt(Object v, int r, int k){ data[r][k]=v; }</SPAN>
<SPAN LANG="da-DK">    };</SPAN>
<SPAN LANG="da-DK"><B>    jTable1.setModel(new DatamodelFraHjaelpeklasse());</B></SPAN>

<SPAN LANG="da-DK"><I>    // ... eller bruge standardklassen DefaultTableModel der s&oslash;rger for</I></SPAN>
<SPAN LANG="da-DK"><I>    // det hele (men ikke altid helt som man vil ha' det)...</I></SPAN>
<SPAN LANG="da-DK"><I>    //jTable1.setModel(new DefaultTableModel(data,kolonner));</I></SPAN>

<SPAN LANG="da-DK"><I>    /////////////////////////////////////////////////</I></SPAN>
<SPAN LANG="da-DK"><I>    // <B>Oprettelese af pr&aelig;sentationsobjekter</B></I></SPAN>
<SPAN LANG="da-DK"><I>    /////////////////////////////////////////////////</I></SPAN>

<SPAN LANG="da-DK">    <I>// brug et Farvepraesentation-objekt til kolonnen &quot;Yndlingsfarve&quot;</I></SPAN>
<SPAN LANG="da-DK">    TableCellRenderer <B>farvepr&aelig;sentation = new Farvepraesentation();</B></SPAN>
<SPAN LANG="da-DK"><B>    jTable1.getColumn(&quot;Yndlingsfarve&quot;).setCellRenderer( farvepr&aelig;sentation );</B></SPAN>

<SPAN LANG="da-DK">    <I>// brug et Talpraesentation-objekt til kolonnen &quot;Yndlingstal&quot;</I></SPAN>
<SPAN LANG="da-DK">    TableCellRenderer <B>talpr&aelig;sentation = new Talpraesentation();</B></SPAN>
<SPAN LANG="da-DK"><B>    jTable1.getColumn(&quot;Yndlingstal&quot;).setCellRenderer( talpr&aelig;sentation );</B><BR></SPAN>

<SPAN LANG="da-DK"><I>    /////////////////////////////////////////////////</I></SPAN>
<SPAN LANG="da-DK"><I>    // <B>Oprettelse af redigeringsobjekter</B></I></SPAN>
<SPAN LANG="da-DK"><I>    /////////////////////////////////////////////////</I></SPAN>

<SPAN LANG="da-DK">    <I>// Lav en valgliste til at v&aelig;lge mellem retterne.</I></SPAN>
<SPAN LANG="da-DK">    JComboBox comboBox = new JComboBox();</SPAN>
<SPAN LANG="da-DK">    comboBox.addItem(&aelig;ble);</SPAN>
<SPAN LANG="da-DK">    comboBox.addItem(asparges);</SPAN>
<SPAN LANG="da-DK">    comboBox.addItem(banan);</SPAN>
<SPAN LANG="da-DK">    comboBox.addItem(broccoli);</SPAN>
<SPAN LANG="da-DK">    comboBox.addItem(gulerod);</SPAN>
<SPAN LANG="da-DK">    comboBox.addItem(kiwi);</SPAN>
<SPAN LANG="da-DK">    comboBox.addItem(l&oslash;g);</SPAN>
<SPAN LANG="da-DK"><B>    jTable1.getColumn(&quot;Yndlingsret&quot;).setCellEditor(</B></SPAN>
<SPAN LANG="da-DK"><B>                                              new DefaultCellEditor(comboBox));</B></SPAN>

<SPAN LANG="da-DK">    <I>// Og en til v&aelig;lge mellem enlig og ikke-enlig.</I></SPAN>
<SPAN LANG="da-DK">    comboBox = new JComboBox();</SPAN>
<SPAN LANG="da-DK">    comboBox.addItem( new Boolean(true));</SPAN>
<SPAN LANG="da-DK">    comboBox.addItem( new Boolean(false));</SPAN>
<SPAN LANG="da-DK"><B>    jTable1.getColumn(&quot;Enlig?&quot;).setCellEditor(new DefaultCellEditor(comboBox)</B>);</SPAN>
<SPAN LANG="da-DK">  }</SPAN>
<SPAN LANG="da-DK">}</SPAN></PRE><H2 CLASS="western">
6.7 <a name='afsn6.7'></a>Avanceret: Udseendet af Swing</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/kapitel6.jsp#afsn6.7">
  <input type='checkbox' name='vis' value='6.7'>Jeg erklærer, at jeg allerede har købt bogen<br />
  <input type='checkbox' name='vis' value='6.7'>Jeg lover at anskaffe den i nær fremtid.<br />
  <input type='submit' value='Vis mig dette afsnit'>
  </form>

	  <H3 CLASS="western">6.7.1 <a name='afsn6.7.1'></a>Swing-komponenters standardudseender</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/kapitel6.jsp#afsn6.7.1">
  <input type='checkbox' name='vis' value='6.7.1'>Jeg erklærer, at jeg allerede har købt bogen<br />
  <input type='checkbox' name='vis' value='6.7.1'>Jeg lover at anskaffe den i nær fremtid.<br />
  <input type='submit' value='Vis mig dette afsnit'>
  </form>

	  <H3 CLASS="western">
6.7.2 <a name='afsn6.7.2'></a>Andre udseender</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/kapitel6.jsp#afsn6.7.2">
  <input type='checkbox' name='vis' value='6.7.2'>Jeg erklærer, at jeg allerede har købt bogen<br />
  <input type='checkbox' name='vis' value='6.7.2'>Jeg lover at anskaffe den i nær fremtid.<br />
  <input type='submit' value='Vis mig dette afsnit'>
  </form>

	  <H3 CLASS="western">6.7.3 <a name='afsn6.7.3'></a>Kunststoff-udseendet</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/kapitel6.jsp#afsn6.7.3">
  <input type='checkbox' name='vis' value='6.7.3'>Jeg erklærer, at jeg allerede har købt bogen<br />
  <input type='checkbox' name='vis' value='6.7.3'>Jeg lover at anskaffe den i nær fremtid.<br />
  <input type='submit' value='Vis mig dette afsnit'>
  </form>

	  <H3 CLASS="western">6.7.4 <a name='afsn6.7.4'></a>Alloys-udseendet</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/kapitel6.jsp#afsn6.7.4">
  <input type='checkbox' name='vis' value='6.7.4'>Jeg erklærer, at jeg allerede har købt bogen<br />
  <input type='checkbox' name='vis' value='6.7.4'>Jeg lover at anskaffe den i nær fremtid.<br />
  <input type='submit' value='Vis mig dette afsnit'>
  </form>

	  <H3 CLASS="western">6.7.5 <a name='afsn6.7.5'></a>Opgaver</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/kapitel6.jsp#afsn6.7.5">
  <input type='checkbox' name='vis' value='6.7.5'>Jeg erklærer, at jeg allerede har købt bogen<br />
  <input type='checkbox' name='vis' value='6.7.5'>Jeg lover at anskaffe den i nær fremtid.<br />
  <input type='submit' value='Vis mig dette afsnit'>
  </form>

	  

<a href='http://javabog.dk/'>javabog.dk</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='kapitel5.jsp'>&lt;&lt; forrige</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='indhold.jsp'>indhold</a>&nbsp;&nbsp;|&nbsp;&nbsp;<a href='kapitel7.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>
