Enrera
Mòdul 6
Iniciació a la programació en Java
  Pràctica
1
2
3
4
   
Exercicis
Exercicis
 
 
  Els applets
   
  Una de les causes de l'enorme popularitat de Java és que permet construir petites (a vegades molt grans!) aplicacions, el codi de les quals resideix en un servidor web i es transmet per la xarxa, executables en el si dels navegadors (Internet Explorer, Netscape Navigator, Mozilla, etc.) com a elements de pàgines HTML. Aquestes petites aplicacions són els applets i ara hi treballarem.
   
 

Pel que fa als applets, cal considerar dos aspectes:

  • L'elaboració de l'applet com a tal, que és el procés general d'elaboració d'una aplicació Java: escriptura del codi font i compilació.

  • Què ha de contenir la pàgina HTML per tal que, quan es carregui al navegador de l'usuari, també es carregui i s'executi l'applet.
Tractarem aquestes dues qüestions separadament.
   
Les etiquetes (tags) HTML per a applets:
   
Atenció ! És força senzill. Al punt del document HTML on vulguem que aparegui l'applet, hi hem de posar el codi:
   
 

    <APPLET
        CODE="el_meu_applet.class"
        WIDTH="500"
        HEIGHT="300"
    >
    </APPLET>

   
  i, des del punt de vista del llenguatge HTML, un applet es comporta com una imatge, és a dir, pot centrar-se, incloure en una taula, etc.
   
  La classe que es cita després de l'atribut CODE= és la classe principal de l'applet. I si hem comprimit tot l'applet en un fitxer *.jar, cosa que d'altra banda és absolutament recomanable, el codi és:
   
      <APPLET
        CODE="el_meu_applet.class"
        ARCHIVE="el_meu_fitxer_comprimit.jar"
        WIDTH="500"
        HEIGHT="300"
    >
    </APPLET>
   
  El tag <APPLET> admet molts d'altres atributs. Podeu veure'n la llista completa a la pàgina "The APPLET Tag" del tutorial oficial de Sun, "The Java Tutorial", descarregable des de http://java.sun.com., si no és que ja ho havíeu fet...
   
  Tot construint applets...
   
Pràctica

Anem a construir el nostre primer applet. Al JCreator, definim el projecte AppletFacil, però ara com a "Basic Java Applet" en lloc de "Basic Java Application" com havíem fet fins ara. Immediatament i automàtica, JCreator crea el fitxer AppletFacil.java, que és l'applet, i un document HTML, AppletFacil.htm, que és on es veurà l'applet.

Aquests fitxers són suficients per tal que la cosa funcioni i, per tant, ja podem compilar-los. Per veure'n el resultat, tenim dues opcions:

   
 
  • Executar-lo des de JCreator, el qual, automàticament, ens el mostra mitjançant l'eina AppletViewer.exe (es el que farem mentre els nostres applets estiguin en construcció). El resultat és aquest:


  • Demanar el document HTML, AppletFacil.htm, amb el navegador. El resultat és aquest:
   
   
Però, com estan fets els applets?
   
Atenció !

Vegem-ne els punts principals:

   
 
  • Un applet és sempre una classe filla de la classe java.applet.Applet. Això vol dir que cal importar el package java.applet i que la definició de la classe és:

    public class el_meu_applet extends Applet { ...

  • La classe java.applet.Applet és filla de la classe java.awt.Panel ( filla de java.awt.Container). Per tant, hi podem posar els components que ens vingui de gust: més pannells, botons, canvas, etc. El layout manager per defecte és java.awt.FlowLayout, però podem canviar això i definir el que mes ens convingui.

  • Quan la Màquina Virtual de Java del navegador es disposa a executar un applet, es dirigeix al mètode public void init () de l'applet. En certa forma, el paper del mètode init en els applets és el del mètode public void main(String[] args) de les aplicacions Java autònomes: tot allò que posaríem al mètode main, ho hem de posar ara al mètode init.
  • Una qüestió pel que fa a seguretat: Un applet no pot gestionar ni fitxers ni d'altres recursos que no resideixin al servidor en el qual també resideix el document HTML que el conté. Per tant, amb un applet no es poden llegir ni escriure fitxers de la màquina on s'executa (la màquina client). Aquesta és una limitació molt severa, però que ens protegeix dels applets maliciosos que podrien funcionar com a virus...
Pràctica Vist això, ara convertirem una aplicació que ja tenim, la de l'"editor de missatges" (projecte, Missatgeria02, pràctica 5, mòdul 5) en un applet:
   
  Copiem el fitxer etiquetes.java a la carpeta AppletFacil i l'afegim al projecte (poseu el mouse sobre el nom del projecte i premeu el botó de la dreta). Al fitxer AppletFacil.java que ens havia fet JCreator, hi esborrem el mètode public void paint (Graphics g) que no ens és necessari, omplim el mètode public void init() i hi afegim la classe ElMeuPanel. El codi ha de quedar com el que mostrem a continuació: en groc hem marcat el codi que serà diferent del projecte Missatgeria02, l'altre queda exactament igual:
   
  /*
* @(#)AppletFacil.java 1.0 02/11/02
*
* You can modify the template of this file in the
* directory ..\JCreator\Templates\Template_2\Project_Name.java
*
* You can also create your own project template by making a new
* folder in the directory ..\JCreator\Template\. Use the other
* templates as examples.
*
*/

import java.awt.*;

  import java.awt.event.*;
  import java.applet.*;

public class AppletFacil extends Applet {

    public void init() {
          setBackground(Color.LIGHT_GRAY);
        ElMeuPanel panel=new ElMeuPanel(this);
        add(panel,BorderLayout.CENTER);
      }

}

class ElMeuPanel extends Panel implements ActionListener,
                                          ItemListener {
      AppletFacil applet;
      Label labelNomDestinatari;
    Label labelNomRemitent;
    TextField fieldNomDestinatari;
    TextField fieldNomRemitent;
    Button ok;
    Button enviar;
    List listInici;
    List listFinal;
    TextArea text;
    int numIdioma=Etiquetes.idiomaInicial;
    Choice idioma;
      public ElMeuPanel(AppletFacil f) { //constructor
          super();
          applet=f;
          setLayout(new BorderLayout());

        Panel panelNord=new Panel();
        panelNord.setLayout(new BorderLayout());

        Panel panelLabels=new Panel();
        panelLabels.setLayout(new GridLayout(2,1));
        labelNomDestinatari=new Label("",Label.RIGHT);
        labelNomRemitent=new Label("",Label.RIGHT);
        panelLabels.add(labelNomDestinatari);
        panelLabels.add(labelNomRemitent);
        panelNord.add(panelLabels,BorderLayout.WEST);

        Panel panelNoms=new Panel();
        panelNoms.setLayout(new GridLayout(2,1));
        fieldNomDestinatari=new TextField();
        fieldNomDestinatari.addActionListener(this);
        fieldNomRemitent=new TextField();
        fieldNomRemitent.addActionListener(this);
        panelNoms.add(fieldNomDestinatari);
        panelNoms.add(fieldNomRemitent);
        panelNord.add(panelNoms,BorderLayout.CENTER);

        ok=new Button();
        ok.addActionListener(this);
        panelNord.add(ok,BorderLayout.EAST);
        add(panelNord,BorderLayout.NORTH);

        text=new TextArea("");
        add(text,BorderLayout.CENTER);

        Panel panelCortesia=new Panel();
        panelCortesia.setLayout(new GridLayout(2,1));

        listInici=new List();
        listInici.addActionListener(this);
        panelCortesia.add(listInici);

        listFinal=new List();
        listFinal.addActionListener(this);
        panelCortesia.add(listFinal);

        add(panelCortesia,BorderLayout.WEST);

        Panel panelSur=new Panel();
        panelSur.setLayout(new GridLayout(1,2));

        idioma=new Choice();
        idioma.addItemListener(this);
        panelSur.add(idioma);

        enviar=new Button();
        enviar.addActionListener(this);
        panelSur.add(enviar);

        add(panelSur,BorderLayout.SOUTH);

        canviaIdioma();
    }

    public void actionPerformed(ActionEvent e) {
        Object objAction=e.getSource();
            if (objAction instanceof TextField ||
                objAction instanceof List) {
                preparaText();
            } else if (objAction instanceof Button) {
                    if(objAction==ok) {
                        preparaText();
                    } else if(objAction==enviar) {
                        enviaMissatge();
                    }
            }
    }

    public void itemStateChanged(ItemEvent e) {
        numIdioma=idioma.getSelectedIndex();
        canviaIdioma();
    }

    public void canviaIdioma() {

  //     mainFrame.setTitle(Etiquetes.titolFrame[numIdioma]); Com que
                                                         // ja no hi
                                                         // ha cap
                                                         // frame
                                                         // cal
                                                         // eliminar
                                                         // aquesta
                                                         // línia
          labelNomDestinatari.setText(Etiquetes.nomTo[numIdioma]);
        labelNomRemitent.setText(Etiquetes.nomFrom[numIdioma]);
        ok.setLabel(Etiquetes.ok[numIdioma]);
        listInici.removeAll();
        int totalHis=Etiquetes.hi[numIdioma].length;
            for (int i=0;i<totalHis;i++) {
                listInici.add(Etiquetes.hi[numIdioma][i]);
            }
        listInici.select(1);
        listFinal.removeAll();
        int totalByes=Etiquetes.bye[numIdioma].length;
            for (int i=0;i<totalByes;i++) {
                listFinal.add(Etiquetes.bye[numIdioma][i]);
            }
        listFinal.select(1);
        idioma.removeAll();
        int totalIdiomes=Etiquetes.idiomes.length;
            for (int i=0;i<totalIdiomes;i++) {
                idioma.add(Etiquetes.idiomes[numIdioma][i]);
            }
        idioma.select(numIdioma);
        enviar.setLabel(Etiquetes.enviar[numIdioma]);
        preparaText();
          applet.validate();
      }

    public void preparaText () {
        text.setText(listInici.getSelectedItem()+
        fieldNomDestinatari.getText()+
                            ",\n\n < . . . "+
                            Etiquetes.espaiText[numIdioma]+
                            " . . . >\n\n"+
                            listFinal.getSelectedItem()+
                            ",\n "+
                            fieldNomRemitent.getText());
    }

    public void enviaMissatge() {
        System.out.println(text.getText());
    }

}

   
  Un cop compilat, prèvia modificació dels atributs WIDTH i HEIGHT del tag <APPLET> al fitxer AppletFacil.htm, l'executem amb l'AppletViewer:
   
   
  o bé, obrim el fitxer AppletFacil.htm amb el navegador:
   
   
   
  Classes i mètodes abstractes:
   
Atenció !

Aprofitarem que ja sabem fer applets i inclourel's en documents HTML per reprendre un fil que s'havia iniciat a la pràctica 2 del mòdul 3, a l'introduir la classe java.util.Vector, continuat a la pràctica 3 del mòdul 4:

  • Es tracta de fer un applet amb un sol canvas pel qual hi puguem moure tot d'objectes amb el mouse. La presentació (amb AppletViewer) serà aquesta:


    i podeu comprovar-ne el funcionament tot clicant aquí. La imatge la obtindreu aquí.

  • L'esquema general de funcionament serà aquest:

    • Cadascun dels sis objectes que apareix sobre el canvas és una instància d'alguna de les tres classes trastets.Rodoneta, trastets.Finestra o trastets.Postal. El propi nom de les classes ja indica que estaran agrupades en el package trastets. Per tant, a l'encapçalament del fitxer (un fitxer per a cadascuna!) del codi hi ha d'haver la clàusula package trastets.

    • Cadascuna d'aquestes tres classes tindrà, com a variables de classe,

      • la variable java.awt.Dimension posicio, que contindrà informació quant a la posició (les coordenades) de l'objecte en el canvas, i

      • la variable java.awt.Rectangle rectangle, que contindrà informació quant a la zona clickable de l'objecte.

    • Com a mètodes, a part el constructor, cadascuna d'aquestes tres classes tindrà:

      • public void pinta (Canvas canvas,Graphics g), que descriurà com pintar l'objecte sobre el canvas canvas en el context gràfic g.

      • public void setPosicio (Dimension pos), que posarà la variable posicio al valor pos i recalcularà la zona clickable rectangle.

      • public void setOcupacio (), que recalcularà la zona clickable rectangle, a partir del valor de la variable posicio.

      • public Dimension getPosicio (), mitjançant el qual podrem demanar el valor de la variable posicio.

      • public Rectangle getOcupacio (), mitjançant el qual podrem demanar el valor de la variable rectangle.

    • Els objectes es desaran en un vector. Tal com ja vam fer a la pràctica 3 del mòdul 4, com que cadascuna de les dues variables i cadascun dels cinc mètodes a cadascuna de les tres classes, a més de compartir nom, comparteixen funció: pintar, situar, etc. (que no funcionament, aquest és propi de cada classe),és lògic fer que les tres classes siguin filles d'una única classe mare, la qual ja tindrà aquestes variables i aquests mètodes definits. Per tal d'estalviar espai de memòria en una nova classe sense més funcions que engendrar classes filles i passar-les-hi mètodes per herència, aquesta classe mare s'ha de declarar com a abstracta, mitjançant la clàusula abstract. El codi per a aquesta classe, trastets.Trasto (projecte AppletNoTanFacil, "Basic Java Applet", fitxer Trasto.java) és aquest:

      package trastets;

      import java.awt.*;

      public abstract class Trasto { // Declaració com a classe
                                     // abstracta


          Dimension posicio;
          Rectangle ocupo;

          public Trasto (int x,int y) { //constructor
              posicio=new Dimension(x,y);
              ocupo=new Rectangle(0,0,0,0);
          }

          public abstract void pinta (Canvas canvas,Graphics g);

          public void setPosicio (Dimension pos) {
              posicio=pos;
              setOcupacio();
          }

          public abstract void setOcupacio ();

          public Dimension getPosicio () {
              return posicio;
          }

          public Rectangle getOcupacio () {
              return ocupo;
          }

      }


    • Dels cinc mètodes que té la classe mare trastets.Trasto i que heretaran les classes filles, n'hi ha que tenen un funcionament exactament igual per a cada classe filla i n'hi ha que no.

      • Els que tenen un funcionament exactament igual per a cada classe filla ja es poden codificar a la classe mare. Són els mètodes public void setPosicio (Dimension pos), public Dimension getPosicio () i public Rectangle getOcupacio ().

      • Els mètodes que tenen un funcionament específic per a cada classe filla es declaren abstractes (mitjançant la clàusula abstract) i no s'hi posa cos. Són els mètodes public abstract void pinta (Canvas canvas,Graphics g) i public abstract void setOcupacio (). Naturalment, cada classe filla els ha de sobreescriure (override) amb el seu propi codi.

    • El codi per a les tres classes filles és aquest:

      package trastets;

      import java.awt.*;

      public class Rodoneta extends Trasto {

          int radi;

          public Rodoneta (int x,int y,int r) { //constructor
              super(x,y);
              radi=r;
              setOcupacio();
          }

          public void pinta (Canvas canvas,Graphics g) {
              g.setColor(Color.BLACK);
              g.fillOval(ocupo.x,ocupo.y,
                         ocupo.width,ocupo.height);
              g.setColor(Color.RED);
              g.fillOval(ocupo.x+3,ocupo.y+3,
                         ocupo.width-6,ocupo.height-6);
          }

          public void setOcupacio () {
              ocupo.x=posicio.width-radi;
              ocupo.y=posicio.height-radi;
              ocupo.height=2*radi;
              ocupo.width=2*radi;
          }

      }


      package trastets;

      import java.awt.*;

      public class Finestra extends Trasto {

          int ample,alt;

          public Finestra (int x,int y,
                           int amp,int al) { //constructor
              super(x,y);
              ample=amp;
              alt=al;
              setOcupacio();
          }

          public void pinta (Canvas canvas,Graphics g) {
              g.setColor(Color.ORANGE);
              g.fill3DRect(ocupo.x,ocupo.y,
                           ocupo.width,ocupo.height,
                           true);
              g.fill3DRect(ocupo.x+10,ocupo.y+8,
                           ocupo.width-20,ocupo.height-16,
                           false);
              g.fill3DRect(ocupo.x+ocupo.width/2-2,ocupo.y+8,
                           4,ocupo.height-16,
                           true);
              g.fill3DRect(ocupo.x+10,ocupo.y+ocupo.height/2-2,
                           ocupo.width-20,4,
                           true);
          }

          public void setOcupacio () {
              ocupo.x=posicio.width;
              ocupo.y=posicio.height;
              ocupo.width=ample;
              ocupo.height=alt;
          }

      }


      package trastets;

      import java.awt.*;

      public class Postal extends Trasto {

          int ample,alt;
          Image imatge;

          public Postal (int x,int y,int amp,int al,
                         Image im) { //constructor
              super(x,y);
              ample=amp;
              alt=al;
              imatge=im;
              setOcupacio();
          }

          public void pinta (Canvas canvas,Graphics g) {
              g.drawImage(imatge,
                          ocupo.x,ocupo.y,
                          ocupo.width,ocupo.height,
                          canvas);
          }

          public void setOcupacio () {
              ocupo.x=posicio.width;
              ocupo.y=posicio.height;
              ocupo.width=ample;
              ocupo.height=alt;
          }

      }


      Observeu com a cap de les tres classes ni s'hi declaren les variables Dimension posicio i Rectangle ocupo, ni els mètodes public void setPosicio (Dimension pos), public Dimension getPosicio () i public Rectangle getOcupacio (). La raó és que ja estan declarats, definits i codificats a la classe mare trastets.Trasto!

  • La classe que farà funcionar tot això serà un applet. Aquest applet contindrà només un canvas (ElMeuCanvas) al qual se li implementen les interfícies java.awt.event.MouseListener i java.awt.event.MouseMotionListener. El codi és aquest:

    /*
    * @(#)AppletNoTanFacil.java 1.0 02/11/03
    *
    * You can modify the template of this file in the
    * directory ..\JCreator\Templates\Template_2\Project_Name.java
    *
    * You can also create your own project template by making a new
    * folder in the directory ..\JCreator\Template\. Use the other
    * templates as examples.
    *
    */

    import java.awt.*;
    import java.awt.event.*;
    import java.util.*;
    import java.applet.*;
    import java.net.*;
    import trastets.*;

    public class AppletNoTanFacil extends Applet {

        public void init() {
            setLayout(new BorderLayout());
            ElMeuCanvas canvas=new ElMeuCanvas(this);
            add(canvas,BorderLayout.CENTER);
        }

    }

    class ElMeuCanvas extends Canvas implements MouseListener,
                                                MouseMotionListener {

        AppletNoTanFacil applet;
        Image imEncaraNoEsVeu;
        Vector trastos;
        Trasto trastoPescat=null;
        int posX,posY;

        public ElMeuCanvas (AppletNoTanFacil ap) { //constructor
            super();
            applet=ap;
            addMouseListener(this);
            addMouseMotionListener(this);
            trastos=new Vector();
            afegeixTrasto(new Rodoneta(30,50,12));
            afegeixTrasto(new Finestra(75,125,90,60));
            afegeixTrasto(new Rodoneta(245,175,19));
            afegeixTrasto(new Finestra(315,5,90,120));
            Toolkit toolkit=Toolkit.getDefaultToolkit();
            URL url=getClass().getResource("imatges/bosch.jpg");
            Image imatge=toolkit.getImage(url);
            MediaTracker mediaTracker=new MediaTracker(this);
            mediaTracker.addImage(imatge,0);
                try {
                    mediaTracker.waitForAll();
                        while(!mediaTracker.checkAll()) {
                        }
                } catch (InterruptedException e) {
                    System.out.println("No puc!");
                }
            afegeixTrasto(new Postal(295,145,189,149,imatge));
            afegeixTrasto(new Postal(215,15,63,50,imatge));
            setBackground(new Color(255,255,200));
        }

        public void afegeixTrasto (Trasto tr) {
            trastos.addElement(tr);
        }

        public void update (Graphics g) {
            paint(g);
        }

        public void paint (Graphics g) {
            Dimension size=getSize();
                if (imEncaraNoEsVeu==null) {
                    imEncaraNoEsVeu=createImage(1024,768);
                }
            Graphics gEncaraNoEsVeu=imEncaraNoEsVeu.getGraphics();
            gEncaraNoEsVeu.setColor(getBackground());
            gEncaraNoEsVeu.fillRect(0,0,size.width,size.height);
                for(Enumeration enum=trastos.elements();
                    enum.hasMoreElements();){
                    Object ob=enum.nextElement();
                    Trasto tr=(Trasto)ob;
                    tr.pinta(this,gEncaraNoEsVeu);
                }
            g.drawImage(imEncaraNoEsVeu,0,0,this);
        }

        public void mouseClicked (MouseEvent e) {
        }

        public void mousePressed (MouseEvent e) {
            posX=e.getX();
            posY=e.getY();
                for(Enumeration enum=trastos.elements();
                    enum.hasMoreElements();){
                    Object ob=enum.nextElement();
                    Trasto tr=(Trasto)ob;
                    Rectangle oc=tr.getOcupacio();
                        if (oc.contains(posX,posY)) {
                            trastoPescat=tr;
                            break;
                        }
                }
        }

        public void mouseReleased (MouseEvent e) {
            trastoPescat=null;
        }

        public void mouseEntered (MouseEvent e) {
        }

        public void mouseExited (MouseEvent e) {
        }

        public void mouseDragged (MouseEvent e) {
            int gX=e.getX();
            int gY=e.getY();
                if (trastoPescat!=null) {
                    int dX=gX-posX;
                    int dY=gY-posY;
                    Dimension posicio=trastoPescat.getPosicio();
                    trastoPescat.setPosicio(new Dimension(
                               posicio.width+dX,posicio.height+dY));
                    repaint();
                    posX=gX;
                    posY=gY;
                }
        }

        public void mouseMoved (MouseEvent e) {
        }

    }


    Observem:

    • Com sempre que s'implementen interfícies, la classe ElMeuCanvas ha de tenir definits tots els mètodes de les interfícies que implementa, encara que, alguns d'ells no es facin servir. Nosaltres concentrarem tota la funcionalitat en els mètodes public void mousePressed (MouseEvent e), public void mouseReleased (MouseEvent e) i public void mouseDragged (MouseEvent e).

    • Els objectes que passegem pel canvas estan guardats en un vector: la variable de classe Vector trastos. Al construir el canvas, s'afegeixen aquests objectes al vector mitjançant el mètode public void afegeixTrasto (Trasto tr).

    • El mètode public void paint (Graphics g) utilitza la tècnica del doble buffering (vegeu la pràctica anterior). Recupera els objectes que hi ha al vector trastos mitjançant una instància de java.util.Enumeration,

      Object ob=enum.nextElement(); // Recordeu que els objectes,
                                    // en un vector, s'hi guarden
                                    // com a instàncies de
                                    // java.lang.Object!

      fa la conversió (casting) corresponent,

      Trasto tr=(Trasto)ob;

      els pinta sobre la
      imatge oculta imEncaraNoEsVeu, fent servir el seu context gràfic gEncaraNoEsVeu i, quan ha esgotat el contingut del vector, pinta la imatge imEncaraNoEsVeu amb el context gràfic g propi del canvas, que ja és visible a l'usuari.

    • El mètode public void mousePressed (MouseEvent e) serveix per a determinar si hem premut el botó esquerre del mouse just quan el cursor és sobre un objecte. Amb la mateixa tècnica que la del mètode public void paint (Graphics g), recupera els objectes que hi ha al vector trastos i mira si l'esdeveniment s'ha produït dins del rectangle que representa la zona clickable de l'objecte:

      Trasto tr=(Trasto)ob; // Casting imprescindible!
      Rectangle oc=tr.getOcupacio(); // Zona clickable de l'objecte
          if (oc.contains(posX,posY)) { // La zona clickable conté
                                        // el punt clickat?

              trastoPescat=tr; // Identifiquem quin és aquest
                               // objecte

              break; // Ja no cal seguir mirant. Trenquem el cicle
          }

      En el cas que sí s'hagi produït, llavors identifica l'objecte, en guarda la
      referència (tr) a la variable de classe Trasto trastoPescat, i acaba el procés d'identificació.

    • El mètode public void mouseReleased (MouseEvent e) estableix com a null l'objecte identificat pel mètode anterior.

    • El mètode public void mouseDragged (MouseEvent e) canvia el valor de la variable Dimension posicio de l'objecte identificat, la referència del qual és a la variable de classe Trasto trastoPescat, en funció del moviment del cursor del mouse. Llavors, mitjançant repaint(), demana el repintat inmediat del canvas.

  • El codi del document HTML en el qual apareixerà l'applet és aquest:

    <HTML>
    <HEAD>
    </HEAD>
    <BODY BGCOLOR="000000">
    <CENTER>
    <APPLET
        code = "AppletNoTanFacil.class"
        width = "500"
        height = "300"
    </APPLET>
    </CENTER>
    </BODY>
    </HTML>
   
  Applets amb paràmetres:
   
Un applet té la capacitat de llegir paràmetres externs (de la mateixa manera que una aplicació Java els llegeix mitjançant el mètode public static void main (String[] args)). El mètode, que és de la classe java.applet.Applet, és public String getParameter(String nom).

Els paràmetres, que sempre es llegeixen com a cadenes (strings), han de ser al codi del document HTML que conté l'applet, dintre de l'etiqueta <APPLET>. La sintaxi es fa present a la variació següent de l'exemple anterior.
   
Pràctica

Anem a modificar l'exemple anterior de manera que el color del fons (background) del canvas sigui definit per uns certs paràmetres:

  • Al codi del document HTML, dins de l'etiqueta <APPLET> hi afegim els paràmetres:

    <HTML>
    <HEAD>
    </HEAD>
    <BODY BGCOLOR="000000">
    <CENTER>
    <APPLET
        code = "AppletNoTanFacil.class"
        width = "500"
        height = "300"
        <param name="RGBr" value="255">
        <param name="RGBg" value="255">
        <param name="RGBb" value="220">
    </APPLET>
    </CENTER>
    </BODY>
    </HTML>

    Els noms dels paràmetres, "RGBr", "RGBg" i "RGBb" són, evidentment, arbitraris. Aquí hem posat aquests perquè es refereixen a cadascun dels components, vermell, verd i blau, d'un color RGB. Observeu-ne la sintaxi:

    <param name="nom_del_paràmetre" value="valor_del_paràmetre">

  • Ara hem de canviar el codi de l'applet per tal que sigui capaç de llegir els paràmetres. Anem al mètode constructor del canvas i hi afegim:

            int rgbR=Integer.parseInt(applet.getParameter("RGBr"));
            int rgbG=Integer.parseInt(applet.getParameter("RGBg"));
            int rgbB=Integer.parseInt(applet.getParameter("RGBb"));
            setBackground(new Color(rgbR,rgbG,rgbB));

    després de comentar o suprimir la línia que definia el color del fons (background)

            // setBackground(new Color(255,255,200));

    El mètode que es crida és public String getParameter(String nom)de applet, que és l'applet que conté el canvas. Com que el resultat n'és una cadena (string) i el necessitem com a int per a construir el color, caldrà aplicar el mètode static (de la classe java.lang.Integer) public static int parseInt(String st).
   
  Ara per a molt atrevits/des!
   
L'ús de paràmetres per a controlar el comportament dels applets pot arribar a ser molt i molt sofisticat. Aquí proposem un exemple, una variació de l'exemple anterior, mitjançant el qual els objectes que es carreguen al vector trastos es defineixen com a paràmetres:
   
Pràctica
  • Comencem per afegir el codi marcat en groc clar al document HTML:

    <HTML>
    <HEAD>
    </HEAD>
    <BODY BGCOLOR="000000">
    <CENTER>
    <APPLET
        code = "AppletNoTanFacil.class"
        width = "500"
        height = "300"
        <param name="RGBr" value="255">
        <param name="RGBg" value="255">
        <param name="RGBb" value="220">
        <param name="trasto0" value="Rodoneta,30,50,12">
        <param name="trasto1" value="Finestra,75,125,90,60">
        <param name="trasto2" value="Rodoneta,245,175,19">
        <param name="trasto3" value="Finestra,315,5,90,120">
        <param name="trasto4"
             value="Postal,295,145,189,149,imatges/bosch.jpg">
        <param name="trasto5"
             value="Postal,215,15,63,50,imatges/bosch.jpg">
    </APPLET>
    </CENTER>
    </BODY>
    </HTML>

    Observeu com el valor de cada paràmetre és una cadena (string) que conté el nom i totes les dades necessàries per a construir un objecte de la classe d'aquest nom. Observeu també la regla que hem seguit pels noms de cada paràmetre, que després aprofitarem per a llegir-los i per saber que ja no hi ha més paràmetres d'aquesta mena.

  • Al mètode constructor del canvas, hi suprimim totes les línies dedicades a omplir el vector amb objectes i les substituïm per una única línia, la qual crida a un nou mètode, public void llegeixTrastos(), especialitzat en llegir els paràmetres, interpretar-los, construir els objectes corresponents i posar-los al vector trastos.

        public ElMeuCanvas (AppletNoTanFacil ap) { //constructor
            super();
            applet=ap;
            addMouseListener(this);
            addMouseMotionListener(this);
            trastos=new Vector();
            llegeixTrastos();
            int rgbR=Integer.parseInt(applet.getParameter("RGBr"));
            int rgbG=Integer.parseInt(applet.getParameter("RGBg"));
            int rgbB=Integer.parseInt(applet.getParameter("RGBb"));
            setBackground(new Color(rgbR,rgbG,rgbB));
        }

  • El mètode, public void llegeixTrastos() aprofita el mètode public String[] split (String str) de la classe java.lang.String (vegeu-ne la documentació) per partir la cadena llegida en trossos, just on hi ha el caràcter ",":

    public void llegeixTrastos () {
        int i=0;
            while (true) {
                String nom="trasto"+String.valueOf(i);
                String valor=applet.getParameter(nom);
                    if (valor==null) {
                        break;
                    } else {
                        String[] trossos=valor.split(",");
                            if (trossos[0].equals("Rodoneta")) {
                                int x=Integer.parseInt(trossos[1]);
                                int y=Integer.parseInt(trossos[2]);
                                int r=Integer.parseInt(trossos[3]);
                                afegeixTrasto(new Rodoneta(x,y,r));
                            } else
                            if (trossos[0].equals("Finestra")) {
                                int x=Integer.parseInt(trossos[1]);
                                int y=Integer.parseInt(trossos[2]);
                                int a=Integer.parseInt(trossos[3]);
                                int h=Integer.parseInt(trossos[4]);
                                afegeixTrasto(new Finestra(x,y,a,h));
                            } else
                            if (trossos[0].equals("Postal")) {
                                int x=Integer.parseInt(trossos[1]);
                                int y=Integer.parseInt(trossos[2]);
                                int a=Integer.parseInt(trossos[3]);
                                int h=Integer.parseInt(trossos[4]);
                                Toolkit toolkit=
                                    Toolkit.getDefaultToolkit();
                                URL url=getClass().getResource(
                                                   trossos[5]);
                                Image imatge=toolkit.getImage(url);
                                MediaTracker mediaTracker=
                                    new MediaTracker(this);
                                mediaTracker.addImage(imatge,0);
                                    try {
                                        mediaTracker.waitForAll();
                                            while(
                                              !mediaTracker.checkAll(
                                              )) {
                                            }
                                    } catch (
                                      InterruptedException e) {
                                    }
                                afegeixTrasto(new Postal(
                                                  x,y,a,h,imatge));
                            }
                    }
                i++;
            }
    }
  Ara se us invita a modificar el document HTML per tal de tenir diversos objectes i distribucions sobre el canvas...
   
  Com continua això ara?
   
Atenció !

Ara segurament ja esteu en el punt en el qual començareu a queixar-vos que construir una GUI (Graphic User Interface) per a una aplicació Java és una feina, si no titànica, prou complicada!

Anem a pams. Aquest mòdul i l'anterior han estat una introducció a l'AWT (Abstract Windows Toolkit) i, ambdós, tenien dos objectius didàctics:

  • d'una banda, l'objectiu obvi d'introduir-vos en el maneig de les classes de l'AWT per tal que arribeu a ser capaços de construir GUIs...

  • i de l'altra, donat que les classes de l'AWT són molt elementals, aprofitar això per mostrar-vos i fer-vos practicar alguns dels paradigmes de la programació orientada a objectes (OOPS)

Però l'AWT és només una part del conjunt de les Java Foundation Classes (JFC), les quals, segons la pṛpia empresa Sun, "són un conjunt de llibreries de classes Java, part de la distribució J2SE (Java 2 Standard Edition, que és la que fem servir aquest curs) per a permetre la construcció d'interfícies gràfiques d'usuari (GUI) i funcionalitat gràfica per a aplicacions client ("Java applications") basades en la tecnologia Java." (vegeu http://java.sun.com/products/jfc/ )

Quant a la funcionalitat gràfica, el conjunt JFC ens proporciona les següents APIs:

  • L'AWT (Abstract Windows Toolkit), ja prou discutit aquí, que permet als nostres programes d'integrar-se en el sistema windows natiu de la plataforma en la qual s'executin (MS Windows, Linux, Unix, etc.),

  • Java 2D, per a gràfics bidimensionals amb cert grau de sofisticació, imatges, text i impressió.

  • Swing, que és una extensió de l'AWT, la qual ens proporciona una col·lecció molt important de classes gens elementals, que inclouen d'origen moltes funcionalitats que amb les classes de l'AWT caldria construir a ma. Les classes de Swing que són extensió de les de l'AWT solen tenir el mateix nom que les de l'AWT, però precedit d'una J: JLabel, JApplet, JPanel, etc. Els paquets que les contenen són javax.swing.*.
Naturalment, si és que esteu seriosament interessats en aplicacions gràfiques de Java, siguin applets o aplicacions autònomes, us convindrà un estudi detallat del paquet javax.swing. A la pràctica 1 i als exercicis del mòdul 7 hi proposem l'ús d'una classe de Swing.
   
   
 
Amunt