Mòdul 4   

Pràctica 5: Java més enllà de BlueJ
Tornar presentació tema
    Pràctica 1 Pràctica 2 Pràctica 3 Pràctica 4 Pràctica 5
     
  En aquesta pràctica veurem les possiblitats que ens dóna per exportar les aplicacions de Java a fi i efecte d'executar-les fora de l'entorn de programació. Els applets, o miniaplicacions, que són petits programes que s'executen a través dels navegadors d'internet i els arxius jar, executables des de qualsevol plataforma que suporti Java.  
     
 

Els applets

 
     
 

Quan va néixer Internet, una de les principals funcions de la xarxa era l'intercanvi de documentació entre usuaris en un sistema d'hipertext. La web era un gran magatzem d'unitats documentals, les pàgines web, que s'enllaçaven les unes amb les altres a través del llenguatge de marcació HTML i es recolzaven en definicions d'estils senzilles per a enriquir el seu aspecte.

A mesura que Internet anava creixent i es multiplicaven els seus usos, el llenguatge HTML es va demostrar insuficient per a resoldre les noves necessitats de la web. Feien falta llenguatges que fessin possible incloure programació a les pàgines. El primer llenguatge en satisfer aquesta demanda va ser Java. Netscape, el navegador més popular als anys noranta del segle passat, incorporava una màquina virtual de Java que feia possible córrer applets, petites aplicacions de Java incrustades a la pàgina web. Els applets van fer famós Java i van facilitar també un salt qualitatiu a Internet.

D'aquells temps ençà ha canviat molt el panorama: els applets no són ja l'aspecte més potent, o si més no més destacable, de Java i la web s'ha enriquit posteriorment amb llenguatges de programació més lleugers i rendibles com el JavaScript o el Flash.

Malgrat tot, els applets són encara força populars, especialment en programes de complexitat mitjana o, en entorns empresarials, com a marc per a interfícies gràfiques riques .

Afegir un applet a una pàgina web és una tasca força senzilla. Si el teu navegador disposa de màquina virtual de Java, en aquests moments estaràs observant un applet en funcionament després d'aquest paràgraf.

 
     
 
 
     
 

Per a afegir-lo a aquesta pàgina he escrit les línies següents al codi font de la pàgina html, just en el lloc on vull que es vegi l'applet:

 
     
  <APPLET CODE=rush WIDTH=400 HEIGHT=280>
<param name="highScore" value="0">
<param name="highScoreID" value="200">
</APPLET>
 
     
 

i he posat els fitxers .class i de recursos de l'applet a la mateixa carpeta que la pròpia pàgina web.

A veure si t'en surts amb el nivell 12!

 
 
  Els applets des de BlueJ    
     
  El nostre entorn de treball BlueJ està preparat per a treballar amb applets. En podem escriure i després visualitzar-los fàcilment amb el visor d'applets del kit de java o a través d'una pàgina web. Tot seguit et proposem que facis una prova i veuràs que el procés de visualització es fa amb un sol clic de ratolí.  
     

Baixa't el projecte pingpong. Desempaqueta'l on tens per costum deixar els teus projectes en una carpeta amb el nom pingpong.

Quan l'obris amb el , obtindràs una visió similar a aquesta:

 
 
     
   
     
  Tens una classe que es diu pingpong. El BlueJ l'ha etiquetat com a <<applet>>. Obre el codi font de la classe i observa'n l'encapçalement:  
     
  public final class pingpong extends Applet
    implements Runnable, MouseListener, MouseMotionListener
    {
 
     
 

La classe Applet és una subclasse de la classe Panel. La classe Panel és un contenidor gràfic genèric que està en el paquet awt, un paquet del SDK de Java que conté les eines gràfiques de base del llenguatge.

Com que en aquests mòduls no hem fet encara programació gràfica, el codi font de l'applet pingpong et resultarà críptic, però pots intentar desxifrar-lo.

De moment ens conformarem amb executar el programa: posa el cursor sobre la classe pingpong i pica amb el botó dret. Tria la primera opció, Executar applet i tot segit el BlueJ t'obrirà una finestra com aquesta:

 
     
 
 
     
 

Tria Executar applet en un navegador web i deixa les altres variables per defecte.

  • Amb alçada i amplada defineixes el número de punts que té el panel a la pàgina web: amb 500 x 500 el programa es veurà bé.
  • Sovint els applets necessiten llegir paràmetres per arrencar. La patalla anterior també permetria passar paràmetres a l'applet, però no és el cas de l'applet pingpong.

I tot seguit:

  • Si el teu navegador té activa la màquina virtual de Java, el t'obrirà una pàgina web com aquesta:
 
 
 
     
 

i ja pots jugar al ping pong contra la màquina i intentar fer una puntuació récord.

  • Ara bé, si el teu navegador no porta màquina de java, intenta arrencar l'applet amb l'opció del Executar applet en el visualitzador d'applets. L'applet s'engegarà en una finestra del windows.
 
     
  Ara faràs el teu applet    
     
 

Ara escriuràs un applet modest: un generador d'aforismes que pots posar en el capçal d'una pàgina web per a fer-la més trascendent.

Crea un nou projecte del que es digui aforismes. Crea-hi una nova classe amb el nom aforisme. Ja saps que has de clicar sobre l'opció Nova classe.. però ara tria l'opció Applet de la llista de classes possibles: l'entorn de treball ja et crearà la carcassa d'un applet des d'una plantilla predefinida.

Obre l'editor del codi de la classe; et proposem que hi afegeixis dos elements:

  • una matriu d'aforismes
  • un mètode que pinta al panel de l'applet un aforisme triat a l'atzar.

En primer lloc la matriu d'aforismes:

 
     
 

public class aforisme extends JApplet
{
// variables d'instància- reemplaceu el següent exemple per les
// vostres variables en aquest cas els aforismes amb què "jugareu"

    private int x;
    private String[] frases =
    {
    "Cal no oblidar que tota política que no fem nosaltres "+
    "serà feta contra nosaltres",
    "Temeu l'home d'un sol periòdic",
    "Si en aquest món hi ha una cosa intrínsecament dolenta "+
    "és, sens dubte, l'Estat",
    "El millor govern, quin pot ser? Aquell que ens ensenya "+
    "a governar-nos nosaltres mateixos",
    "Ningú no crida més reclamant la llibertat de premsa "+
    "que aquell qui vol abusar-ne",
    "No hi ha res més monstruós que una ignorància activa",
    "El qui actua no té mai consciència; només en té el "+
    "qui medita",
    "L´amor a la veritat es mostra sabent trobar i apreciar "+
    "la bondat a tot arreu",
    "Els aforismes –els meus com els de tothom- són "+
    "sempre falsos, intrinsecament falsos. I aquest també",
    "'De la discussió naix la llum', diuen. I "+
    "l’experiència demostra que, efectivament, "+
    "cadascú sol quedar-se amb les mateixes conviccions "+
    "que tenia abans de discutir, però més clares.",
    "Forma part d’una bona educació saber en quantes "+
    "ocasions cal ser maleducat",
    "De tota manera, és aconsellable que "+
    "envelleixis simultaniament amb el teu cos"
    };

 
     
 

Poseu veure que la matriu l'afegim com a camp de la classe.
Va per sota del camp int x que ens ha escrit per defecte el .

Ara afegim el mètode que genera i pinta un aforisme triat a l'atzar cada cop que s'executa o es refresca l'applet. L'escriuràs després del darrer mètode de la classe.

 
     
  public void paint( Graphics g ) {
    Random rand = new Random();
    int n = 11;
    int i = rand.nextInt(n+1);
    g.drawString( frases[i],25,25 ) ;
}
 
     
  Afegeix la sentència d'importació:  
     
  import java.util.Random;  
     
 

al començament de la classe perquè el programa reconegui el generador de nombres a l'atzar.

Desa la classe i la compiles. Executa-la amb el i l'opció des del navegador web: podràs veure que cada cop que refresquis la pàgina web, l'applet ens mostra un aforisme diferent.

 
     

Si tens coneixements d'elaborar pàgines web i tens ganes de practicar una mica més, escriu una pàgina web aforismes.html i intenta incrustar-hi el codi html necessari perquè es carregui l'applet aforisme. Recorda que has d'utilitzar l'etiqueta <APPLET> i que aforisme.class ha d'estar, en principi, a la mateixa carpeta on escriguis la pàgina web.

El resultat ha de ser semblant a aquest:

 
   

 
  Actualitza la pàgina del teu navegador i observa com varia l'aforisme mostrat.  
     
     
  Executar aplicacions fóra del BlueJ  
     
 

El és un IDE (entorn integrat de desenvolupament ) extremadament còmode per a crear instàncies de classe, arrencar programes, passar paràmetres o veure les relacions entre els diferents objectes. La major part d'usuaris, però, no el tenen instal·lat als seus ordinadors i necessitaran altres formes per arrencar els programes Java.

En aquesta secció aprendràs a preparar els teus programes perquè es puguin executar des de qualsevol ordinador que tingui instal·lada una màquina virtual de Java. Necessitaràs tenir en consideració dos qüestions:

  • Has d'afegir un mètode main a l'aplicació.

  • Has d'exportar el programa a un fitxer .jar amb el .
 
     
  El mètode main    
     
 

En totes les pràctiques que has fet fins ara has treballat en projectes que contenen una o més classes i has activat els programes creant instàncies de les classes i executant els seus mètodes des d'una interfície gràfica. Es tracta d'una forma fàcil i gratificant d'interactuar amb Java, però no és el mecanisme convencional d'activació de programes del llenguatge.

Perquè un programa pugui ser arrencat per una màquina de Java, és imprescindible que una de les seves classes tingui escrit un mètode main. Quan demanem l'execució del programa la màquina virtual busca, en el cos de la classe que intentem executar, el mètode main. Si el troba, executa el codi que hem escrit a l'interior del mètode, si no el troba, falla l'execució del programa.

Per demostrar el funcionament d'aquest mètode, escriuràs un nou projecte que ens servirà per a saber el temps que ha passat des d'una data fins ara.

 
     
Crea un nou projecte a la carpeta de projectes amb el nom quanttemps i afegeix una nova classe amb el nom QuantTemps. Ha de tenir el codi següent:  
     
  import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import java.text.SimpleDateFormat;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
* Calcula, en diferents mesures, el temps que ha passat
* des d'una data fins ara
*
* @author Angel Solans
* @version 03-06-2004
*/

public class QuantTemps {

    // una línia
    private static String LINIA
          = "--------------------------------";

    /**
    * Mètode que arrenca el programa
    */

    public static void main(String[] args) throws IOException {
        // L'entrada des del teclat
        BufferedReader entrada = new BufferedReader(
            new InputStreamReader(System.in));
        // La data Actual
        Calendar ara;
        // La data a comparar
        Calendar anterior;
        // El formatador de dates
        SimpleDateFormat df
            = new SimpleDateFormat("dd-MM-yyyy");
        // Creem els objectes de calendari
        anterior = new GregorianCalendar();
        anterior.setTime(new Date());
        ara = new GregorianCalendar();
        ara.setTime(new Date());

        // Fem els càlculs amb la previsió d'errors
        String sdata="";
        while (!sdata.equals("x")) {
            System.out.println("Introdueix una data en "+
                "format dd-mm-yyyy p.ex: 12-05-2004."+
                " x per sortir");
            sdata = entrada.readLine();
            if (!sdata.equals("x")) {
            try {
                anterior.setTime(df.parse(sdata));
                if (anterior.before(ara)) {
                    System.out.println("Des de les 0 hores de la "+
                    " data "+sdata+" han passat: ");
                    System.out.println(LINIA);

                    long difMillis = ara.getTimeInMillis()-
                       anterior.getTimeInMillis();
                    long difSecs = difMillis/(1000);
                    long difMins = difMillis/(60*1000);
                    long difHores = difMillis/(60*60*1000);
                    long difDies = difMillis/(24*60*60*1000);
                    double difMesos = difDies/30.0;
                    double difAnys = difDies/365.0;

                    System.out.println(difAnys+" anys");
                    System.out.println(difMesos+" mesos");
                    System.out.println(difDies+" dies");
                    System.out.println(difHores+" hores");
                    System.out.println(difMins+" minuts");
                    System.out.println(difSecs+" segons");

                    System.out.println(LINIA);

                } else {
                    System.out.println("La data triada és "+
                       "posterior a la data actual");
                }
            }catch(Exception e) {
                System.out.println(
                  "Format de data incorrecte, "+
                  "és vàlid dd-mm-yyyy. Torna-ho a intentar");
            }
            }
        }

    }
}

 
 

 

 
 

Observa l'únic mètode que hem creat:

    public static void main(String[] args) throws IOException {

Quan executem el programa QuantTemps, la màquina de Java el buscarà i n'executarà el seu contingut. Com pots veure, es tracta d'un mètode static. Recordes el que vol dir, oi? És un mètode que no s'instancia, és compartit per tots els objectes de la classe. També vol dir que des del mètode main només podràs accedir als mètodes static de la classe.

Molts cops, per a evitar aquest problema, la classe que conté el mètode main d'un programa només conté aquest mètode i poc més; es deixa el gruix de l'aplicació a altres classes que són instanciades dins del mètode main.

En el nostre exemple, al mètode main li hem afegit una excepció: throws IOException. No és obligatori; ara bé, li hem posat perquè li farem llegir des d'un dispositiu d'entrada, el teclat, i podríem generar error. D'aquesta manera es comprova l'entrada i en cas que no sigui correcte es genera un missatge però no s'atura el programa.

La feina del mètode main de la nostra aplicació és molt senzilla:

  • Llegeix una data que entrem des del teclat (BufferedReader) , la compara amb la data actual i, a partir de la transformació de les dates a un valor en mil·lisegons que fa el sistema, n'extreu successivament el nombre de segons, minuts, hores, dies i una aproximació al nombre de mesos i d'anys.
  • Si entrem la data en un format incorrecte, l'aplicació ens ho indica.
  • Si posem una data futura, també rebrem un avís.
  • L'aplicació va acceptant dates en un bucle que no s'atura fins que no entrem com a data simplement una x.

Pots verificar el funcionament del programa executant el mètode main des de la classe. Recorda que no has d'instanciar cap objecte de la classe perquè main és un mètode static. El BlueJ obrirà una finestra etiquetada amb "Mètode que arrenca el programa". Pica sobre el boto "Accepta" i observa i interactua amb la cònsola.

 

 
     
  Exportant l'aplicació    
     
 

Ara que ja tenim escrita l'aplicació l'exportarem amb el i l'executarem directament des de la cònsola, si treballes amb Windows, desde la finestra de comandes, si treballes amb Línux, des d'un terminal.

Tria l'opció de menú Projecte | Exportar i escull les següents opcions:

 
 
 
     
 

Amb aquest procediment ja hem creat llibreries, ara creem una aplicació: observa que definim una classe principal QuantTemps. El seu mètode main serà el cridat quan executem l'aplicació. Cliquem sobre continuar. El ens demana que triem un nom pel fitxer .jar i una ubicació en el nostre disc dur per a l'aplicació. Jo li he posat com a nom comptartemps.jar i l'he deixat a l'arrel del c:\. Ara ja tinc a punt el programa per a executar-lo des de la consola.

Com vam comentar en la pràctica 2 del mòdul 1, Per a executar un programa Java has de cridar el programa java.exe que està en el directori /bin del teu kit de Java, per exemple, c:/j2sdk/bin/java.exe. Si has afegit aquest directori al path del sistema, podràs cridar java.exe des de qualsevol carpeta de l'ordinador. És una opció que et recomanem.

Obre una línia de comandes al teu sistema i crida l'aplicació:

 
 
 
 
  • He fet c:/java -jar comptartemps.jar des de la carpeta arrel c:/ perquè he exportat a aquesta ubicació el fitxer comptartemps.jar i tinc el directori /bin del SDK de Java al path del sistema.
  • Si no és així, has de canviar de carpeta amb la comanda cd fins a situar-te on tinguis comptartemps.jar i cridar java.exe d'una forma similar a aquesta:
                   

No oblidis explicitar l'opció -jar, que indica a la màquina de Java que treballa amb un fitxer empaquetat.

Si tot surt bé, el programa et demanarà que entris una data. He posat la data de naixement de Kurt Cobain. En el moment que escrivís una x com a "data" llavors es tancaria l'aplicació.

Si Kurt Cobain fos viu, quan es redactaven aquests materials tindria 37 anys....

 
     
     

Si has analitzat la manera com es compten els mesos i els anys que han passat (dividint el nombre de dies, respectivament, per 30 o per 365) segurament pensaràs que és una certa aproximació però que és una informació que pot ser que no concordi del tot amb el que estem acostumats a dir. I tampoc no és usual (degut al diferent nombre de dies que tenen els mesos o al fet que hi ha anys que són de traspàs) donar una mesura de temps amb decimals de "mesos de 30 dies" o d'"anys de 365 dies".

De fet, Java ens ho posa molt fàcil, per a obtenir una sortida similar a la següent:

 

 
  només ens cal reemplaçar el còmput de mesos i anys per una expressió com la següent:  
 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

// Locale és una classe amb formats locals
import java.util.Locale;

import java.text.SimpleDateFormat;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
* Calcula, en diferents mesures, el temps que ha passat
* des d'una data fins ara
*
* @author Angel Solans
* @version 03-06-2004
*/
public class QuantTemps {

    // una línia
    private static String LINIA
          = "--------------------------------";

    /**
    * Mètode que arrenca el programa
    */
    public static void main(String[] args) throws IOException {
        // L'entrada des del teclat
        BufferedReader entrada = new BufferedReader(
            new InputStreamReader(System.in));
        // La data Actual
        Calendar ara;
        // La data a comparar
        Calendar anterior;
        // El formatador de dates
        SimpleDateFormat df
            = new SimpleDateFormat("dd-MM-yyyy");
        // Creem els objectes de calendari
        anterior = new GregorianCalendar();
        anterior.setTime(new Date());
        ara = new GregorianCalendar();
        ara.setTime(new Date());

        // Fem els càlculs amb la previsió d'errors
        String sdata="";
        while (!sdata.equals("x")) {
            System.out.println("Introdueix una data en "+
                "format dd-mm-yyyy p.ex: 12-05-2004."+
                " x per sortir");
            sdata = entrada.readLine();
            if (!sdata.equals("x")) {
            try {
                anterior.setTime(df.parse(sdata));
                if (anterior.before(ara)) {
                    System.out.println("Des de les 0 hores de la "+
                    " data "+sdata+" han passat: ");
                    System.out.println(LINIA);

                    long difMillis = ara.getTimeInMillis()-
                       anterior.getTimeInMillis();
                    long difSecs = difMillis/(1000);
                    long difMins = difMillis/(60*1000);
                    long difHores = difMillis/(60*60*1000);
                    long difDies = difMillis/(24*60*60*1000);
                    double difMesos = difDies/30.0;
                    double difAnys = difDies/365.0;

//                    System.out.println(difAnys+" anys");
//                    System.out.println(difMesos+" mesos");
                    System.out.println(difDies+" dies");
                    System.out.println(difHores+" hores");
                    System.out.println(difMins+" minuts");
                    System.out.println(difSecs+" segons");

                    System.out.println(LINIA);

                    Date datanaixement= df.parse(sdata);                     // Obtenim la data d'avui  
                    Calendar age =
                       Calendar.getInstance(Locale.getDefault());
                    age.setTimeInMillis(
                        Math.abs(datanaixement.getTime()-
                        System.currentTimeMillis()));
                    System.out.println("Des de la data "+sdata+
                        " s'han complert :");
                    // Calculem el número d'anys i mesos fins ara.
                    System.out.println(age.get(Calendar.YEAR)-1970+
                        " anys i "+age.get(Calendar.MONTH)+
                        " mesos ");


                } else {
                    System.out.println("La data triada és "+
                       "posterior a la data actual");
                }
            }catch(Exception e) {
                System.out.println(
                  "Format de data incorrecte, "+
                  "és vàlid dd-mm-yyyy. Torna-ho a intentar");
            }
            }
        }