Java Programierung
Kap.14:   APPLETS (Applet)

Kapitel-Index
  14.1   Java-Applets (applet) in HTML-Dokumenten
  14.1.1    Text-Graphik 
  14.1.2    Bild-Graphik, Maus 
  14.1.3    Layout 
  14.1.4    Dialog 
  14.1.5    Farben (Color)
  14.2   Testfragen
14.1     Java-Applets (applet) in HTML-Dokumenten

  Ein Applet ist ein innerhalb eines HTML-Texts ablaufendendes (appliziertes) Programm mit Eingabe per Maus und/oder Textfeld. Es wird aufgerufen mit einem Applet-fähigen Browser und ist angepasst an die Fenstertechnik der jeweiligen Benutzeroberfläche. Superklasse ist die im Paket java.applet vereinbarte Klasse
                        java.applet.Applet                     ,
selbst direkte bzw. indirekte Subklasse der im Paket java.awt (Abstract Window Toolkit) vereinbarten Klassen Panel, Container und Component. Die aktuelle HTML-Version, für dieses Buch 4.01, unterstützt das traditionelle applet-Element, z.B.
 <applet code="MyApplet.class" width="636" height="400"></applet>
zum Aufruf eines Java-Applets, das als class-file übersetzt ist. In künftigen HTML- und XHTML-Versionen ist für Multimedia-Anwendungen einschließlich Applets das object-Element vorgesehen. Das code-Attribut gibt den Pfad und den Namen des Applets mit der Endung .class an. Der Pfad kann entfallen, wenn der class-file im aktuellen Verzeichnis steht. width-Attribut und height-Attribut geben die Breite und Höhe der Darstellung in Pixeln an, die im Applet abgefragt werden können,
            int width=getWidth(), height=getHeight();           .
  In diesem Buch wird als Breite width="636" gewählt, die Maximalbreite für Druck im Hochformat mit den verwendeten Browsern (Mozila Firefox, Internet Explorer).

  Zwischen applet-Tag und applet-EndTag können param-Tags (stets ohne EndTag) angeben werden, z.B.
                 <param name="myParam" value="4711">            ,
deren value-Attributwert im Applet abgefragt werden kann, z.B.
                String value=getParameter("myParam");           .

  Für nicht-Applet-fähige Browser, die applet-Tag und applet-EndTag sowie darin enthaltene param-Tags ignorieren, fügen wir zwischen applet-Tag und applet-EndTag normalen HTML-Text ein, z.B.
                             MyApplet                            ,
der von nicht-Applet-fähigen Browsern alternativ ausgedruckt wird, aber von Applet-fähigen Browsern ignoriert wird. Der Internet Explorer ignoriert das Applet zunächst aus "Sicherheitsgründen", druckt also "MyApplet" aus, stellt aber dann auf Wunsch des Benutzers "...Klicken...zulassen...Ja" das Applet dar. Nötigenfalls muss ein Download des JRS (Java Runtime System) erfolgen (Literatur.2).




14.1.1   Text-Graphik

  Im Gegensatz zu Applikationen, bei denen String-Text mit main(String[] args) eingegeben und mit System.out.print(String s) ausgegeben wird, wird in Applets String-Text mit getText() eingegeben und mit setText(s) oder mit drawString(s,x,y) ausgegeben.

  Das folgende Einführungsapplet Listener enthält ein Textfeld TextField txf, einen Knopf Button but und eine Marke Label lab. Die graphischen Komponenten txf, but, lab müssen mit
                   add(txf);add(but);add(lab);
in den Container des Window-Fensters eingefügt werden, um sichtbar gemacht zu werden. Das im Applet voreingestellte FlowLayout, d.h. Layout in Schriftreihenfolge, stellt die graphischen Komponenten dar in der Reihenfolge ihrer add-Einfügung von links nach rechts. Passt eine Komponente in der Folge nicht mehr in die Fensterbreite, dann wird links unter der Komponentenfolge fortgesetzt. Die Komponentenfolgen werden mittig in der Fensterbreite angeordnet.
  Nach dem Observer/Observable-Modell (siehe Paket java.util) beobachtet eine Schnittstelle ActionListener das Applet Listener, das seinerseits den ActionListener und dessen Methode actionPerformed() implementiert und den ActionListener mit der Beobachtung des Knopfs but beauftragt:
                  but.addActionListener(this);
  Wird der Knopf but gedrückt, dann "hört" der ActionListener den Mausklick und ruft die Methode actionPerformed() auf, die den Text aus dem Textfeld txf mit txf.getText() liest und in die Marke lab mit lab.setText(txtf.getText()) schreibt.

  Die Text-Graphik in paint(Graphics g) mit g.drawString(s,x,y) ist nicht Layout-gesteuert, sondern (x,y)-Koordinaten-bestimmt. Die Pixel-Koordinaten (x.y), d.h. x nach rechts und y nach unten, bezeichnen den Anfangspunkt der Basislinie des Strings s. Layout -Graphik "überdeckt" draw-Graphik, d.h. die mit FlowLayout ins Fenster gesetzten Graphiken machen die an gleicher Stelle mit drawString ins Fenster gesetzten Graphiken pixelweise unsichtbar.
//************************ Listener.java *************************
// Lauscht auf Button-Druck und kopiert dann TextField auf Label.*
// Implementiert  die Methode actionPerformed aus ActionListener.*
//   FlowLayout von txf,but,lab ueberdeckt g.drawString(s,x,y).  *
//****************************************************************
//     java.lang.                   O  b  j  e  c  t
import java.awt.event.*;//ActionEvent'||         |||ActionListener   
import java.awt.*; //         Graphics'`Component||`Color
                   //      TextComponent'||`Label|`-Font 
                   // TextField'Container'`Button`--FlowLayout    
import java.applet.Applet; //    Applet'

public class Listener extends Applet implements ActionListener
 {int                size;            // Zeilen- bzw. Zeichenhoehe
  TextField          txf=new TextField("TextField");
  Button             but=new Button   ("Button");
  Label              lab=new Label    (" L a b e l ");
  public void actionPerformed(ActionEvent e)     // ActionListener
   {lab.setText     (txf.getText());              // TextComponent
   }
  public void paint(Graphics g)                // overrides Applet
   {g.setColor      (Color.RED);
    for(int          j=1;j<=3;j++)                     // 3 Zeilen
    for(int          i=0;i<getWidth()*2/size;i++)//width/Zchbreite
     {g.drawString  (""+j,i*size/2,j*size);}   // Zchbreite size/2
   }
  public void start()                          // overrides Applet
   {                 size=getHeight()/3;               // 3 Zeilen
    setFont(new Font("SansSerif",Font.BOLD,size));    // Component
    add             (txf);                            // Container
    add             (but);                            // Container
    add             (lab);                            // Container
    but.addActionListener(this);                  // this Listener              
   }                                              // calls paint()
 }                             // FlowLayout is default for Applet
//****************************************************************

Fig.14.1.1a.gif
Fig. 14.1.1a: Listener Darstellung
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"   >
<!--***************** Listener.html ***************************-->
    <meta http-equiv="content-type"
             content="text/html;charset=ISO-8859-15"             >
    <title>           Listener                            </title>
    <applet     code="Listener.class" width="636" height="192"   >
                      Listener
    </applet>
<!--***************** width=Hochformat height=3*size **********-->
  Im folgenden Beispiel FontChoice werden Schrift-Fonts ausgewählt mit dem Auswahl-Menu der Klasse java.awt.Choice.
//*********************** FontChoice.java ************************
//                   Auswahl des Schrift-Fonts                   *
//****************************************************************
//            java.lang.                        Object
import static java.lang.Integer.parseInt;     // ||||`Integer          
import        java.awt.event.*;      // ItemEvent'||| ItemListener 
import        java.awt.*;     // C o m p o n e n t'|`FlowLayout
                         // Choice'Label'`Container`Font    
import        java.applet.Applet;             // `Applet'
public class FontChoice extends Applet implements ItemListener
 {String[][]ITEM={{"SansSerif","Serif","MonoSpaced"},
                  {"BOLD+ITALIC 3","ITALIC 2","BOLD 1","PLAIN 0"},
                  {"SIZE 30","SIZE 24","SIZE 18","SIZE 12"}};
  int[]           state=new int   [ITEM.length];
  Choice[]        chc  =new Choice[ITEM.length];
  Label           lab  =new Label();

  void set(String name,String style,String size)
   {setFont      (new Font(name,
                  parseInt(style.substring(style.length()-1)),
                  parseInt(size .substring(size .length()-2))));
    String        f=getFont().toString();             // Component
    lab.setText  (f.substring(f.indexOf(',')+1,f.indexOf(']')));
   }
  public void itemStateChanged(ItemEvent e)        // ItemListener
   {loop:for(int  i=0;i<ITEM.length;i++)
         for(int  j=0;j<ITEM[i].length;j++)
          if     (e.getItem().toString().equals(ITEM[i][j]))
                 {state[i]=j;break loop;}
    set(ITEM[0][state[0]],ITEM[1][state[1]],ITEM[2][state[2]]);
   }
  public void start()                          // overrides Applet
   {set(ITEM[0][state[0]],ITEM[1][state[1]],ITEM[2][state[2]]);
    add          (lab);                               // Container
    for(int       i=0;i<ITEM.length;i++)
     {add        (chc[i]=new Choice());               // Container
      for(int     j=0;j<ITEM[i].length;j++)
       {chc[i]   .add(ITEM[i][j]);
       }chc[i]   .addItemListener(this);        // this FontChoice
 } } }                          // FlowLayout is default for Applet
//****************************************************************
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"   >
<!--***************** FontChoice.html *************************-->
    <meta http-equiv="content-type"
             content="text/html;charset=ISO-8859-15"             >
    <title>           FontChoice                          </title>
    <applet     code="FontChoice.class" width="636" height="210" >
                      FontChoice
    </applet>
<!--***************** width=Hochformat height=7*max(size) *****-->
Fig.14.1.1b.gif
Fig. 14.1.1b: FontChoice Darstellung

   Der Konstruktor für die Klasse java.awt.Font (s. Dokumentation)
            Font(String name,int style,int size)
verlangt als erstes Argument einen String für den Font-Namen name, z.B. Familienname "SansSerif" oder "Serif" oder "Monospaced", als zweites Argument einen int-Wert für den Font-Stil style, z.B. 3 (Wert von Font.BOLD+Font.ITALIC) oder 2 (Wert von Font.ITALIC) oder 1 (Wert von Font.BOLD) oder 0 (Wert von Font.PLAIN), und als drittes Argument einen int-Wert für die Font-Pixel-Grösse size, z.B. 30 oder 24 oder 18 oder 12.

  "Serif", diese Bezeichnung entstand am Anfang des 19. Jahrhunderts aus holländisch "schreef" (geschrieben, lat. scribere), ist eine Verschnörkelung mit Fuß-Keilen, die von der babylonischen Keilschrift über das Hebräische auf das späte Römische und gegen Ende des 15. Jahrhunderts auf die deutsche (Schwabacher) Druckschrift übertragen wurde. "Monospaced" Text besteht aus Zeichen gleicher Breite. ITALIC ist eine schräg fließende Handschrift. Der Font-Stil size gibt die Höhe des Textes in Pixeln an.

  Im folgenden Beispiel LaufSchrift enthält das HTML-Dokument LaufSchrift.html ein applet-Element und darin ein param-Element mit Attributen name="text" und value="Laufschrift nach links". Das zugehörige Applet LaufSchrift.java liest den Text auf den String text=getParameter("text"); ein und gibt den Text über die Graphics -Methode g.drawString(text,x,y); wieder aus. Die Breite des Textes ist abfragbar mit der Methode getFontMetrics(Font) aus der Klasse java.awt.FontMetrix.
//********************** LaufSchrift.java ************************
//                    Laufschrift nach links.                    *
//       Der text der Schrift ist als Parameter vorgebbar.       *
//****************************************************************
//            java.lang.                 O  b  j  e  c  t Runnable
import static java.lang.Thread.sleep;   // |         |||`Thread 
import static java.lang.System.err;     // |         ||`System
import        java.awt.*;       // Graphics'Component'`FontMetrics
import        java.applet.Applet;       //   Applet'

public class LaufSchrift extends Applet implements Runnable
 {String       text;
  int          width,textwidth,shift,x,y;
  public void paint(Graphics g)             // overrides Component
   {g.drawString(text,x,y);}
  public void run()                                    // Runnable
   {for(;;)
     {if      (x<=-textwidth)
              {x=width;}                       // Neuanfang rechts
      else    {x-=shift;}                       // Lauf nach links
      try     {sleep(100);}
      catch   (InterruptedException e){err.println(e.toString());}
      repaint ();       // calls update() with 'clear' and paint()
     }
   }
  public void start()                          // overrides Applet
   {           width =getWidth();                     // Component
    int        height=getHeight();                    // Component
    setFont   (new Font("Serif",Font.ITALIC,height*3/4)); // Comp.
               text=getParameter("text");                // Applet
               textwidth=getFontMetrics(getFont())    // Component
                        .stringWidth(text);         // FontMetrics
               shift=textwidth/text.length()/4;  
               x=width;
               y=height*2/3;
    new Thread(this).start();     // this LaufSchrift, calls run()
   }              // calls update() with 'clear' and calls paint()
 }
//****************************************************************

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"   >
<!--***************** LaufSchrift.html ************************-->
    <meta http-equiv="content-type"
             content="text/html;charset=ISO-8859-15"             >
    <title>           LaufSchrift                         </title>
    <applet     code="LaufSchrift.class" width="636" height="180">
      <param    name="text"       value="Laufschrift nach links" >
                      LaufSchrift 
    </applet>
<!--***************** width=Hochformat height=size*4/3 ********-->

Fig.14.1.1c.gif
Fig. 14.1.1c: LaufSchrift Darstellung

  Alle 100 Millisekunden wird der Schirm gelöscht, x um shift nach links verschoben und g.drawString(text,x,y); erneut aufgerufen. Beim Verlassen des linken Randes, d.h. x<=-textwidth, wird der Text wieder rechts neu angesetzt, d.h. x=width.

14.1.2   Bild-Graphik, Maus

  Bild-Graphik des Pakets java.awt (Advanced Windowing Toolkit) wird gestaltet mit Methoden der Klasse Graphics durch Überschreiben der Methode paint(Graphics) der Klasse Component, z.B.
  drawLine(int x1,int y1,int x2,int y2)        (Net, unten)
  fillRect(int x ,int y ,int width,int height) (update, unten)
  drawOval(int x ,int y ,int width,int height) (CupApplet, 1.2.2)
  drawArc (int x ,int y ,int width,int height, 
                  int startAngle,int arcAngle) (CupApplet, 1.2.2)
  Am Anfang ruft ein Applet nacheinander die Methoden init() und start() auf, die leer sind, falls sie nicht vom Programmierer überschrieben wurden. Es folgt der Aufruf der Methode update(Graphics), die den Bildschirm löscht und mit der aktuellen Hintergrundfarbe füllt, im folgenden 'clear' genannt, und die Methode paint(Graphics) aufruft, die leer ist, falls sie nicht vom Programmierer überschrieben wurde.
   public void update(Graphics g)
    {g.setColor(getBackground());            // 'clear', d.h.
     g.fillRect(0,0,getWidth(),getHeight()); // Loeschen  des
     g.setColor(getForeGround());            // Bildschirms
     paint(g);
    }
  Aus dem Programmlauf heraus, z.B. aus einer Listener-Methode, kann durch Aufruf der Methode repaint() die Methode update(Graphics) und implizit die Methode paint(Graphics) aufgerufen werden.

  Am Ende ruft das Applet die Methode stop() auf, die leer ist, falls sie nicht vom Programmierer überschrieben wurde.

  Im folgenden Beispiel Net werden fortlaufend Linien vom Mausdruck-Punkt zu allen vorherigen Mausdruck-Punkten gezogen.

  Damit durch repaint() und implizit durch update(Graphics) nicht die Linien zwischen vorherigen Mausdruck-Punkte gelöscht werden, überschreiben wir update(Graphics) mit einer Version ohne 'clear':
                  public void update(Graphics g)        
                   {paint(g);}
  Es ist nicht möglich, an Stelle von repaint() direkt paint(g) aufzurufen, da an der Aufruf-Stelle im Listener keine Graphics g erklärt ist.
//*************************** Net.java ***************************
//           Durch Mausdruck-Punkte aufgespanntes Netz           *
//****************************************************************
//     java.lang.                           O b j e c t  Iterable
import java.util.Vector;       //           ||     |||`Vector<T>  
import java.awt.event.*;       // MouseEvent'|     ||`MouseAdapter
import java.awt.*;             //   Component'Point'`Graphics
import java.applet.Applet;     //    Applet'

public class Net extends Applet 
 {Point                p;
  Vector<Point>        v=new Vector<Point>();//implements Iterable 

  public void paint(Graphics g)             // overrides Component
   {
    for(Point          each:v)
     {g.drawLine      (p.x,p.y,each.x,each.y);}
   }

  public void update(Graphics g)            // overrides Component
   {
    paint             (g);
   }                     // update() without 'clear' calls paint()

  public void start()                          // overrides Applet
   {
    addMouseListener                                  // Component
     (new MouseAdapter()                    // listen mousePressed
       {public void mousePressed(MouseEvent e)    // MouseListener
         {             p=new Point(e.getX(),e.getY());
          v.addElement(p);
          repaint     ();        // calls update() without 'clear'
         }
       }
     );
   }                             // calls update() without 'clear'
 }

//****************************************************************

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"   >
<!--***************** Net.html ********************************-->
    <meta http-equiv="content-type"
             content="text/html;charset=ISO-8859-15"             >
    <title>           Net                                 </title>
    <applet     code="Net.class" width="636" height="318"        >
                      Net
    </applet>
<!--***************** width=Hochformat height=width/2 *********-->
Fig.14.1.2a.gif
Fig. 14.1.2a: Net Darstellung

  Hätte man im Beispiel Net, ähnlich wie in den Beispielen Listener und FontChoice, die Schnittstelle MouseListener implementiert,
     public class Net extends Applet implements MouseListener   ,
dann hätte man nicht nur die Methode mousePressed(MouseEvent), sondern auch die übrigen Methoden -Clicked, -Entered, -Extended, -Released der Schnittstelle implementieren müssen. Für Schnittstellen mit vielen Methoden, empfiehlt sich die Verwendung eines Adapters, hier MouseAdapter, für den nur die benötigte Methode, hier mousePressed(MouseEvent), implementiert werden muss.

  Im nachfolgenden Beispiel Eyes wird ein Augenpaar durch zwei Kreise dargestellt. In den Augen bewegen sich schwarz gefüllte kleine Kreise als Pupillen so, dass der Eindruck entsteht, als folgten die Augen der Bewegung des Maus-Zeigers. Anders als im vorigen Beispiel Net, in dem die alte Linien-Graphik erhalten blieb und die neue Linie eingefügt wurde, wird in diesem Beispiel die alte Augen-Graphik gelöscht und das Augenpaar neu gezeichnet. Die Methode repaint() ruft die nicht überschriebene Methode update (Graphics) auf, die mit dem Löschen 'clear' des Bildschirms beginnt, bevor sie paint(Graphics) aufruft.
//**************************** Eyes.java *************************
//        Augenpupillen folgen frei bewegter (moved) Maus.       *
//****************************************************************
//     java.lang.                         Object
import java.awt.event.*;       // MouseEvent'||`MouseMotionAdapter
import java.awt.*;             //   Component'`Graphics
import java.applet.Applet;     //    Applet'

public class Eyes extends Applet
 {int           size;                             // Augen-Groesse 
  int[][]       p=new int[2][2];           // Pupillen-Koordinaten
  public void paint(Graphics g)             // overrides Component
   {g.drawOval (size   ,size   ,size  ,size  ); // Augen-Kreisbog.
    g.drawOval (3*size ,size   ,size  ,size  ); //       "
    g.fillOval (p[0][0],p[0][1],size/3,size/3); // Pupill-Kreisfl. 
    g.fillOval (p[1][0],p[1][1],size/3,size/3); //       "
   }
  public void start()                          // overrides Applet
   {            size=getWidth()/5;                    // Component
    addMouseMotionListener  // listenes to mouseMoved(), Component
    (new MouseMotionAdapter()
     {public void mouseMoved(MouseEvent e) // overrides MM-Adapter
       {int[]   m={e.getX(),e.getY()};         // Maus-Koordinaten
        int[][] d={{m[0]-size* 4/3,m[1]-size*4/3},   // Maus-Augen
                   {m[0]-size*10/3,m[1]-size*4/3}};   // Abstaende
        int[]   r={(int)Math.sqrt(d[0][0]*d[0][0]+d[0][1]*d[0][1])
                  ,(int)Math.sqrt(d[1][0]*d[1][0]+d[1][1]*d[1][1])
                  };               // Maus-Augen radiale Abstaende
        for(int i=0;i<2;i++)
        if     (r[i]>size/3)        // falls Maus ausserhalb Auge:
        for(int j=0;j<2;j++)
               {d[i][j]=d[i][j]*size/3/r[i];}  // invert Abstaende
                p=new int[][]
                 {{d[0][0]+size* 4/3,d[0][1]+size*4/3}, 
                  {d[1][0]+size*10/3,d[1][1]+size*4/3}};
        repaint();// calls update() with 'clear' and calls paint()  
       }                 
     }
    );
   }              // calls update() with 'clear' and calls paint()       
 }   
//****************************************************************

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"   >
<!--***************** Eyes.html *******************************-->
    <meta http-equiv="content-type"
             content="text/html;charset=ISO-8859-15"             >
    <title>           Eyes                                </title>
    <applet     code="Eyes.class" width="636" height="382"       >
                      Eyes
    </applet>
<!--***************** width=Hochformat height=width*3/5 *******-->

Fig.14.1.2b.gif
Fig. 14.1.2b: Eyes Darstellung


14.1.3   Layout

  Zum Anordnen von Layout-Komponenten, wie z.B. Fertig-Teile Label, Button, TextField oder Fertig-Menu Choice, werden im Paket java.awt verschiedene Layouts angeboten, die alle die Schnittstelle LayoutManager implementieren,

   FlowLayout    in "Schrift-Reihenfolge"   (Listener, 14.1.1)

   GridLayout    in "Matrix-Reihenfolge"    (Puzzle, 14.1.3)

   BorderLayout  in "Windrosen-Reihenfolge" (DialogApplet, 14.1.3)

   GridBagLayout in "flexibler Reihenfolge" (siehe Dokumentation)

   CardLayout   zum "Karten-Durchblättern"  (siehe Dokumentation)

  Voreingestellt sind FlowLayout für Applet (14) und BorderLayout für Dialog (14.1.4). Bestandteile von Zeilen in FlowLayout werden zentriert angeordnet. Bestandteile von Zeilen in BorderLayout werden linksbündig angeordnet.

  Explizites Setzen eines Layout ist möglich mit der in Container vereinbarten Methode

                     setLayout(LayoutManager)                   .

  Im folgenden Beispiel Puzzle werden Anzeigetasten Button in Gitterform (grid) angeordnet durch Setzen von GridLayout.

//************************* Puzzle.java **************************
// Folge 8..1 umordnen in Folge 1..8 im 3*3 Gitter (GridLayout). *
//    Verschieben der Knoepfe (Button) durch Maus-Anklicken.     *
// Die Gitterabmessungen rows, cols sind als Parameter angebbar. *
//****************************************************************

//            java.lang.                       Object
import static java.lang.Integer.parseInt; //    |||`Integer
import        java.awt.event.*;   // ActionEvent'|| ActionListener 
import        java.awt.*;         //    Component'`GridLayout
                                  // Container'`Button           
import        java.applet.Applet; //  Applet'

public class Puzzle extends Applet implements ActionListener
 {
  int         cols,leng;
  Button[]    b;

  public void actionPerformed(ActionEvent e)     // ActionListener
   {int       n=parseInt(e.getActionCommand()),
              dn=
    /*links*/ n%cols-1>=0   &&b[n-1].getLabel().equals("0")?-1   :
    /*rechts*/n%cols+1<cols &&b[n+1].getLabel().equals("0")? 1   :
    /*oben*/  n-cols>=0  &&b[n-cols].getLabel().equals("0")?-cols:
    /*unten*/ n+cols<leng&&b[n+cols].getLabel().equals("0")? cols:
                                                             0   ;
    if       (dn!=0)
     {b[n+dn].setLabel(b[n].getLabel());           
      b[n+dn].setVisible( true);       // paints button, Component
      b[n]   .setLabel("0");                          
      b[n]   .setVisible(false);       // clears button, Component
     }
   }

  public void start()                          // overrides Applet                 
   {int       rows=parseInt(getParameter("rows"));       // Applet
              cols=parseInt(getParameter("cols"));       // Applet
              leng=rows*cols;
    setFont  (new Font("SansSerif",Font.BOLD,getHeight()/rows));
    setLayout(new GridLayout(rows,cols));             // Container
              b=new Button[leng];
    for(int   i=0;i<leng;i++)
     {        b[i]=new Button      (String.valueOf(leng-i-1));
              b[i].setActionCommand(String.valueOf(i));
              b[i].addActionListener(this);         // this Puzzle
      add    (b[i]);                                  // Container
     }
    b[leng-1].setVisible(false);       // clears button, Component
   }                
 }                      
//****************************************************************

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"   >
<!--***************** Puzzle.html *****************************-->
    <meta http-equiv="content-type"
             content="text/html;charset=ISO-8859-15"             >
    <title>           Puzzle                              </title>
    <applet     code="Puzzle.class" width="636" height="318"     >
      <param    name="rows"         value="3"                    >
      <param    name="cols"         value="3"                    >
                      Puzzle
    </applet>
<!--***************** width=Hochformat height=width/2 *********-->
Fig.14.1.3.gif
Fig. 14.1.3: Puzzle Darstellung

  Der Leser wird im Puzzle ein altes Kinderspiel wiedererkennen. Durch Maus-Anklicken der dem leeren Feld benachbarten Spielsteine verschiebt man die Steine solange, bis sie mit ihren Nummern in Schriftreihenfolge von 1 bis 8 angeordet sind. Die Gestalt rows* cols des Puzzle kann über Parameter-Elemente <param...> und darin gesetzte Attribute name="rows" value="3" und name="cols" value="3" mit getParameter() abgefragt werden.


14.1.4   Dialog  

  Im folgenden Beispiel DialogApplet wird ein Applet erzeugt, das durch Anklicken der Anzeigetaste "Dialog" ein Dialog-Fenster erzeugt und mit setVisible(true) sichtbar macht, siehe actionPerformed(ActionEvent) aus DialogApplet:
                DialogWindow dia=new DialogWindow();
                             dia.setVisible (true);                            
  Im Konstruktor von DialogWindow wird ein neuer Dialog konstruiert mit super(new Frame(),"DialogWindow",true). Durch den Wert true für den dritten Parameter wird bestimmt, dass das Schreiben im auf- rufenden Fenster DialogField blockiert ist, solange DialogWindow geöffnet ist.

  Das DialogWindow dient zum Schreiben eines Textes in das DialogApplet. Dazu schreibt man den Text zunächst in das TextField fld des DialogWindow und klickt auf die Anzeigetaste "Text into DialogApplet".

  Dadurch wird der Text aus dem TextField fld des DialogWindow dia gelesen mit der Methode getText() und in das Label lab des DialogApplets geschrieben mit der Methode setText(String), siehe actionPerformed(ActionEvent) aus DialogApplet:

                    lab.setText(dia.fld.getText());

  Danach wird das DialogWindow mit der Methode dispose() wieder unsichtbar gemacht, siehe actionPerformed(ActionEvent) aus DialogWindow.


  Für Dialog ist BorderLayout voreingestellt (vgl. 14.1.3), d.h. die auf dem Bildschirm erscheinende Fläche von DialogWindow ist unterteilt nach den Himmelsrichtungen.
                 ,----------------------------,
                 |                            |
                 |   N    O    R    T    H    |
                 |                            |
                 |----------------------------| 
                 |        |          |        |
                 |  WEST  |  CENTER  |  EAST  |
                 |        |          |        |
                 |----------------------------|
                 |                            |
                 |   S    O    U    T    H    |
                 |                            |
                 '----------------------------'
  In unserem Beispiel wird in NORTH ein Label "NORTH", in WEST ein Label "TextField:", im CENTER ein TextField fld, in EAST ein Button but und in SOUTH ein Label "SOUTH" eingefügt:

       add(new Label ("NORTH"     ),BorderLayout.NORTH );
       add(new Label ("TextField:"),BorderLayout.WEST  );
       add           (fld          ,BorderLayout.CENTER);
       add           (but          ,BorderLayout.EAST  );                              
       add(new Label ("SOUTH"     ),BorderLayout.SOUTH );

  Für die Abfrage der Bildschirmgröße verwenden wir die Methode getDefaultToolkit() aus der Klasse java.awt.Toolkit.

  Ort und Größe des Dialogs müssen mit setLocation(Point) und setSize(Dimension) festgelegt werden.
//********************** DialogApplet.java ***********************
//        Dialog-Fenster zur TextField-Eingabe ins Applet        *
//****************************************************************
//            java.lang.                 O b j e c t
import        java.awt.event.*;//ActionEvent'|||||| ActionListener
import java.awt.*;       // C o m p o n e n t'||||`FlowLayout
               // TextComponent'Container'||  |||`BorderLayout
               //  TextField'Window'|Label'|  ||`Dimension
               //          Frame'|  |Button'  |`Point 
               //          Dialog'  |         `------,              
import java.applet.Applet;       // `Applet          |
import static java.awt.Toolkit.getDefaultToolkit; // `Toolkit
class DialogWindow extends Dialog implements ActionListener
 {TextField        fld=new TextField(8);
  public DialogWindow()                              // DW constr.
   {super         (new Frame(),"DialogWindow",true); // D  constr.
    Dimension      scr=getDefaultToolkit().getScreenSize();
    setLocation   (new Point(scr.width/7,scr.height/6));    //Comp
    setSize       (new Dimension(scr.width/3,scr.height/6));//Comp
    Button         but=new Button("Text into DialogApplet");
    but.addActionListener(this);              // this DialogWindow
    add(new Label ("NORTH"     ),BorderLayout.NORTH );// Container
    add(new Label ("TextField:"),BorderLayout.WEST  );// Container
    add           (fld          ,BorderLayout.CENTER);// Container
    add           (but          ,BorderLayout.EAST  );// Container                              
    add(new Label ("SOUTH"     ),BorderLayout.SOUTH );// Container
   }
  public void actionPerformed(ActionEvent e)     // ActionListener
   {dispose       ();
   }
 }                           // BorderLayout is default for Dialog
public class DialogApplet extends Applet implements ActionListener
 {Label            lab=new Label(" old Text ");
  public void actionPerformed(ActionEvent e)     // ActionListener
   {DialogWindow   dia=new DialogWindow();
    dia.setVisible(true);                             // Component 
    lab.setText   (dia.fld.getText());            // TextComponent
   }
  public void start()                          // overrides Applet
   {setFont       (new Font("SansSerif",Font.BOLD,getHeight()/4));
    add           (lab);                              // Container
    Button         but=new Button("Dialog");
    add           (but);                              // Container
    but.addActionListener(this);              // this DialogApplet
   }
 }                             // FlowLayout is default for Applet
//****************************************************************
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"   >
<!--***************** DialogApplet.html ***********************-->
    <meta http-equiv="content-type"
             content="text/html;charset=ISO-8859-15"             >
    <title>           DialogApplet                        </title>
    <applet     code="DialogApplet.class" width="636"height="212">
                      DialogApplet
    </applet>
<!--***************** width=Hochformat height=width/3 *********-->
Fig.14.1.4.gif
Fig. 14.1.4: DialogApplet Darstellung


  Jedes Applet, z.B. auch unser DialogApplet, erlaubt "FensterSchließen" durch Anklicken des Window-Leisten-Knopfs "X" ohne explizites Einprogrammieren von dispose().

  Ein Dialog, z.B. unser DialogWindow, ist aber kein Applet und würde für das "Fenster-Schließen" durch Anklicken des DialogWindow - Leisten - Knopfs "X" explizites Einprogrammieren von dispose() erfordern, vgl. CupApplication (3.4). In unserem Fall ist dies nicht erforderlich, da das DialogWindow durch Anklicken von "Text into DialogAplet" schließt, siehe actionPerformed(ActionEvent) aus DialogWindow.






14.1.5   Farben (Color) 

  Auf dem Bildschirm hat jedes Pixel Farbanteile in Rot-Grün-Blau (RGB), auf dem Drucker Farbanteile in Yellow-Magenta-Cyan (YMC).

  Das folgende Beispiel ColorCube erlaubt jede gewünschte Farbkombination als Rot-Grün-Blau-Farbkugel sichtbar zu machen.
//*********************** ColorCube.java *************************
//           Farbwuerfel aus R(ot)G(ruen)B(lau)-Kugeln.          *
// Die Anzahl lums>1 der Farbstufen ist als Parameter vorgebbar. *
//****************************************************************
//            java.lang.                    O  b  j  e  c  t
import static java.lang.Integer.parseInt; //  |         ||`Integer
import        java.awt.*;          // Graphics'Component'`Color 
import        java.applet.Applet;  //     Applet'
public class ColorCube extends Applet
 {int            size,lums,lins;
  int siz(double d)
   {return(int) (d*(size-1)/(lins-1));}     // Groessen-Skalierung
  int col(double d)
   {return(int) (d*255     /(lums-1));}         // Farb-Skalierung
  public void paint(Graphics g)             // overrides Component
   {             size=getWidth();                     // Component
                 lums=parseInt(getParameter("lums"));    // Applet
                 lins=lums*(lums+1);// Kreismittelpunkte u.Raender
    for(int      i=0;i<256;i++)
     {g.setColor(new Color(i,i,i));                
      g.fillPolygon(new int[]{0,(2*size-1)*(255-i)/255,0},
                    new int[]{0,0,(2*size-1)*(255-i)/255},3); 
     }           // grauer Hintergrund diagonal: weiss bis schwarz
    for(int      lin=0;lin<lins;lin++)
     {g.drawLine(0,siz(lin),siz(lins-1),siz(lin));
      g.drawLine(siz(lin),0,siz(lin),siz(lins-1));
     }           // weisse Linien fuer Kreismittelpunkte u.Raender
    for(int      red=0;red<lums;red++)               
    for(int      gre=0;gre<lums;gre++)               
    for(int      blu=0;blu<lums;blu++)               
     {int        r=siz(0.1*red+ 0.3     *lums),           
                 x=siz(0.9*red+(0.2+blu)*lums),     
                 y=siz(0.9*red+(0.2+gre)*lums);     
      g.setColor(new Color(col(red),col(gre),col(blu)));
      g.fillOval(x,y,2*r,2*r);            
      g.setColor(new Color(0,0,0));              
      g.drawOval(x,y,2*r,2*r);            
     }                        // farbige Kreise mit schwarzem Rand
   }
 }                    // implicite start() of Applet calls paint()
//****************************************************************

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"   >
<!--***************** ColorCube.html **************************-->
    <meta http-equiv="content-type"
             content="text/html;charset=ISO-8859-15"             >
    <title>           ColorCube                           </title>
    <applet     code="ColorCube.class" width="636" height="636"  >
      <param    name="lums"            value="5"                 >
                      ColorCube
    </applet>
<!--***************** width=Hochformat height=width=size ******-->

Fig.14.1.5.gif
Fig. 14.1.5: ColorCube Darstellung


  Zum Setzen der Farbe aus Rot-Grün-Blau Anteilen benutzt man die in java.awt.Graphics vereinbarte Methode setColor(Color) und den Konstruktor Color(int,int,int) der Klasse java.awt.Color. Z.B. wird im obigen Applet ColorCube das Schwarz für den Rand der Kreise wie folgt gewählt:

                   g.setColor(new Color(0,0,0));

  Die drei Farbanteile haben jeweils 256 verschiedene Intensitäten von 0..255. Im allgemeinen wird aber ein Bildschirm oder ein Drucker nicht jede Grundfarbe in 256 verschiedenen Nuancen signifikant verschieden darstellen können.

  Im obigen Beispiel Color-Cube wurden vergröbernd nur 5 verschiedene Intensitäten von 0..4 gewählt, um die Anzahl 5*5*5=125 der Farbkugeln so klein zu halten, dass die Farben der Kugeln noch gut zu unterscheiden sind. Durch Wahl eines anderen Werts für das Attribut value im param-Element des applet-Elements können die Intensitäten verändert werden.




14.2     Testfragen

zu    Frage                                  | abdeckbare Antwort
---------------------------------------------+--------------------
                                             |
14.1     Welche 3 Attribute  müssen in einem | code, width, height
      applet-Element immer gesetzt sein?     |
                                             |
14.1     Von welchem Typ sind alle Werte von | vom Typ String 
      Attributen, z.B. width=?, z.B. value=? |   
                                             |
14.1.1/2 In  welchem  Paket  sind  ...Event- | java.awt.event
      und ...Adapter - Klassen vereinbart?   |
                                             |
14.1.1   In welcher Klasse sind add...Liste- | java.awt.Component
      ner-Methoden vereinbart?               |
                                             |
14.1.2   Welche  Methoden werden von start() | update() u. paint()
      und repaint() implizit aufgerufen?     |  
                                             |
14.1.2   Wie  kann  man den clear-Effekt von | update() mit Body
      update() vermeiden?                    |    {paint(g);}
                                             | überschreiben, vgl.
                                             | Beispiel Net
                                             |
14.1.2   Schreibe  ein  Applet,  welches die | siehe mousePressed
      X,Y-Koordinaten bei Mausdruck ausgibt! | mit getX(), getY()
                                             |
14.1.3   In  welchem  Paket  sind ...Layout- | java.awt
      Klassen vereinbart?                    |
                                             |
14.1.3   Welches Layout ist voreingestellt:  |                      
                                             |
      - für Applet ?                         | FlowLayout
      - für Dialog ?                         | BorderLayout
                                             |
14.1.4  Die Klassen Frame, Dialog und Applet |
      eröffnen alle ein Fenster.  Welche der |
      Klassen erlaubt                        |
                                             |
     - automatisches Schließen des Fensters  | Applet, vgl. z.B.
       mit Klick auf das Fensterleisten-X?   |  CupApplet 1.2.2                       
                                             |
     - programmiertes Schließen des Fensters | Frame, vgl. z.B.
       mit  addWindowListener(WindowAdapter) |  CupApplication 3.4
       und  erst  dann  mit  Klick  auf  das | Dialog, vgl. z.B.,                     
       Fensterleisten-X?                     | DialogApplet 14.1.4
                                             |
                                             | betr. new Color():
14.1.5  Zu ColorCube:                        | red->(yel+mag)/2.0                   
     Ändere das red/gre(en)/blu(e)-Modell um | gre->(yel+cya)/2.0
     in ein yel(low)/mag(enta)/cya(n)-Modell | blu->(mag+cya)/2.0
                                             |
    Java Programmierung
  Kap.15