Enrera
Mòdul 6
Iniciació a la programació en Java
  Pràctica
1
2
3
4
   
Exercicis
Exercicis
 
 
  Navegant per un canvas...
   
  A partir d'aquesta pràctica introduirem l'ús dels scrollbars (sí, sí, les barretes verticals i horitzontals que, amb el ratolí, permeten moure's per una àrea). A més, aprendrem a fer més coses amb els canvas i a comprimir tota una aplicació, amb els seus recursos, en un fitxer *.jar, que pot arribar a ser autoexecutable!
   
  Scrollbars
   
Atenció !

Pot esdevenir-se que un component (típicament un canvas) no sigui completament visible a l'usuari simplement perquè no disposa de prou d'espai i algunes zones queden ocultes per d'altres components. La solució estàndard a això és dotar el component de scrollbars, és a dir de barres de moviment vertical i/o horitzontal, les quals permeten navegar per les distintes zones del component.

El paquet java.awt conté una classe, java.awt.ScrollPane, que fa tota la feina:

  • java.awt.ScrollPane és un component i, per tant, pot ser inclòs en el layout manager de qualsevol contenidor (per exemple, un frame o un panel)

  • Però també java.awt.ScrollPane és un contenidor (container), amb layout manager null, destinat a rebre un sol component amb dimensions pròpies. La part del component que es fa visible depèn de la posició (decidida per l'usuari!) dels dos scrollbars que scrollpane incorpora.

  • Si volem construir unl scrollpane (vegeu-ne la documentació), disposem de dos mètodes constructors:

    • public ScrollPane (), que el construeix amb la política (policy) de mostrar o no els scrollbars segons si es necessiten o no.

    • public ScrollPane (int politica), que el construeix amb la política (policy) definida per int politica, que és algun d'aquests valors:

      • ScrollPane.SCROLLBARS_AS_NEEDED,

      • ScrollPane.SCROLLBARS_ALWAYS,

      • ScrollPane.SCROLLBARS_NEVER.

  • Igual que per a qualsevol contenidor, per afegir el component la vista del qual ha de ser comanada pels scrollbars del scrollpane, el mètode és public void add(Component component)
   
Pràctica
Ara farem funcionar tot això: posarem un canvas suficientment gran (900 x 900) en un scrollpane, posat a la posició BorderLayout.CENTER d'un frame més petit que el canvas (600 x 400). Com sempre, creem el projecte Scrolling com a "Basic Java Application" amb el següent codi:
   
  /*
* @(#)Scrolling.java 1.0 02/10/28
*
* You can modify the template of this file in the
* directory ..\JCreator\Templates\Template_1\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.
*
*/
  //package myprojects.scrolling;
 
import java.awt.*;
import java.awt.event.*;

class Scrolling extends Frame {

    public Scrolling() { //constructor
          ScrollPane scrollPane=new ScrollPane();
        Canvas canvas=new ElMeuCanvas();
        canvas.setBackground(new Color(255,255,200));
        canvas.setSize(900,900);
        scrollPane.add(canvas);
        add(scrollPane,BorderLayout.CENTER);
          addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                dispose();
                System.exit(0);
            }
        });
    }

    public static void main(String args[]) {
        System.out.println("Starting Scrolling...");
        Scrolling mainFrame = new Scrolling();

          mainFrame.setSize(600, 400);
        mainFrame.setTitle("Screen roll");
          mainFrame.setVisible(true);
    }

}

 

class ElMeuCanvas extends Canvas {

    public ElMeuCanvas () { //constructor
        super();
    }

    public void paint (Graphics g) {
        Dimension size=getSize();
        g.setColor(Color.RED);
        g.drawRect(2,2,size.width-4,size.height-4);
        g.setColor(Color.BLUE);
            for (int i=5;i<size.width;i=i+30) {
                g.drawOval(10,10,i,i);
            }
        g.setFont(new Font("SansSerif",Font.PLAIN,30));
        g.setColor(Color.BLACK);
        g.drawString("Mou els scrollbars!",150,160);
        g.drawString("Wapo, eh?",300,420);
    }

}

   
  i obtenim això:
   
   
Imatges, fotos, ...
   
Atenció ! Un canvas és capaç de presentar-nos imatges bitmap contingudes en fitxers *.gif o *.jpg. Aquests fitxers poden residir al propi sistema on s'executa l'aplicació (fitxers locals) o a qualsevol node de la xarxa (fitxers remots), del qual es recuperen mitjançant connexions TCP/IP. El SDK de Javaclasses i mètodes per gestionar tot això.
   
  Fitxers locals:
   
Pràctica
  • Comencem per imatges contingudes a fitxers locals. Descarregueu-vos el fitxer bott_001.jpg i poseu-lo a la carpeta classes\imatges del projecte Scrolling. Aquest serà el fitxer a mostrar.

    • És clar que la maquinària que aconseguirà fer visible el fitxer depèn del sistema concret en el qual corre l'aplicació. Cal, doncs, un pont entre l'AWT i el funcionament efectiu del nostre sistema. Aquest pont és la classe java.awt.Toolkit, als mètodes de la qual s'hi recorre directament molt poques vegades, però aquesta n'és una! Començarem per demanar el toolkit per defecte mitjançant el mètode:

      public static Toolkit getDefaultToolkit()

    • Ara ja tenim construït el pont. Demanarem un objecte java.awt.Image per representar la nostra imatge amb el mètode de la classe java.awt.Toolkit:

      public Image getImage(String path_i_nom)

      (Atenció: la separació entre directoris ha de ser "/" i no "\")

    • I, finalment, només cal dibuixar la imatge sobre el canvas. El mètode, de la classe java.awt.Graphics, és

      public abstract boolean drawImage(Image img,
                                        int x,int y,
                                        ImageObserver observer)

      Els paràmetres x i y són la posició de l'angle superior esquerre de la imatge en el canvas i observer és el propi component sobre el qual es dibuixa la imatge, en aquest cas el canvas.

    Tot això, posat en el mètode paint del nostre canvas, ha de quedar així:

        public void paint (Graphics g) {
            Dimension size=getSize();
            Toolkit toolkit=Toolkit.getDefaultToolkit();
            Image image=toolkit.getImage("imatges/bott_001.jpg");
            g.setColor(Color.RED);
            g.drawRect(2,2,size.width-4,size.height-4);
            g.setColor(Color.BLUE);
                for (int i=5;i<size.width;i=i+30) {
                    g.drawOval(10,10,i,i);
                }
            g.setFont(new Font("SansSerif",Font.PLAIN,30));
            g.setColor(Color.BLACK);
            g.drawString("Mou els scrollbars!",150,160);
            g.drawString("Wapo, eh?",300,420);
            g.drawImage(image,0,0,this);
        }

    Com era d'esperar, a l'executar el programa, observem que la imatge tarda una mica en dibuixar-se (s'ha de llegir del disc, tractar-la per tal de convertir-la a pixels, etc.) fins que cobreix tot el hi havia al canvas. Però el procés, tal com està, implica que la Màquina Virtual intenta dibuixar-la vàries vegades mentre, potser, encara no és a punt, cosa que es tradueix en desagradables vibracions del contingut del canvas. Això també (només faltaria!) té solució. Hi ha una classe, java.awt.MediaTracker, que inicia el procés de càrrega i elaboració de les imatges (Image getImage(String path_i_nom) no ho fa!) mitjançant el mètode public void waitForAll() i informa de que tot està ja llest retornant true amb el mètode public boolean checkAll().

    Incorporem això al mètode paint:

        public void paint (Graphics g) {
            Dimension size=getSize();
            Toolkit toolkit=Toolkit.getDefaultToolkit();
            Image image=toolkit.getImage("imatges/bott_001.jpg");
            g.setColor(Color.RED);
            g.drawRect(2,2,size.width-4,size.height-4);
            g.setColor(Color.BLUE);
                for (int i=5;i<size.width;i=i+30) {
                    g.drawOval(10,10,i,i);
                }
            g.setFont(new Font("SansSerif",Font.PLAIN,30));
            g.setColor(Color.BLACK);
            g.drawString("Mou els scrollbars!",150,160);
            g.drawString("Wapo, eh?",300,420);
            MediaTracker mediaTracker=new MediaTracker(this);
            mediaTracker.addImage(image,0);
                try {
                    mediaTracker.waitForAll();
                        if(mediaTracker.checkAll()) {
                            g.drawImage(image,0,0,this);
                        }
                } catch (InterruptedException e) {
                    System.out.println("No puc!");
                }
        }

    i ara la imatge es carrega de manera ben neta.

    La classe, java.awt.MediaTracker té més mètodes, els quals permeten controlar la càrrega simultània de vàries imatges, tot donant-los identificadors. Us recomanem que per a usos més sofisticats d'aquesta classe, en llegiu la documentació amb tota cura.
  Fitxers remots:
   
Pràctica
  • Per fitxers remots, la cosa és una miqueta més complicada, la localització de la imatge (el recurs) és un URL i, aquí, un objecte de la classe java.net.URL (OOP, gent!). En conseqüència, cal:

    • Importar el paquet java.net:

      import java.awt.*;
      import java.awt.event.*;
      import java.net.*;

    • Construir l'URL de la imatge mitjançant el mètode constructor public URL(String protocol_adreça) tenint en compte les excepcions que llença (vegeu-ne la documentació)

    • Construir l'objecte image amb el mètode de java.awt.Toolkit, public Image getImage(URL url).

    El mètode paint, ja suprimit tot allò que després no es veurà, queda així:

        public void paint (Graphics g) {
            Dimension size=getSize();
            Toolkit toolkit=Toolkit.getDefaultToolkit();
            URL url=null;
                try {
                    url=new URL(
           "http://www.xtec.net/~fie00032/d110m5/fitxers/bigboy.jpg"
                               );
                } catch (MalformedURLException e) {
                    System.out.println("No puc trobar la imatge");
                }
            Image image=toolkit.getImage(url);
            MediaTracker mediaTracker=new MediaTracker(this);
            mediaTracker.addImage(image,0);
                try {
                    mediaTracker.waitForAll();
                        if(mediaTracker.checkAll()) {
                            g.drawImage(image,0,0,this);
                        }
                } catch (InterruptedException e) {
                    System.out.println("No puc!");
                }
        }

    i ara, naturalment, la imatge tardarà força més en dibuixar-se!
   
Fitxers Jar i recursos
   
Atenció !

La penúltima versió de Scrolling, la que presenta una imatge llegida des d'un fitxer local, fa servir un recurs local (el fitxer bott_001.jpg). Ja sabem que podem unir i comprimir tots els fitxers *.class necessaris per a una determinada aplicació en un únic fitxer *.jar (vegeu la pràctica 3 del mòdul 2). Però també podem incloure al fitxer *.jar tots els recursos necessaris per a l'aplicació, el fitxer bott_001.jpg en el nostre cas.

Per aconseguir això, cal fer dues coses:

  • Canviar la línia

    Image image=toolkit.getImage("imatges/bott_001.jpg");

    per les línies

    URL url=getClass().getResource("imatges/bott_001.jpg");
    Image image=toolkit.getImage(url);

  • Procurar que, en la construcció del fitxer *.jar, s'hi inclogui el recurs imatges/bott_001.jpg: per exemple, l'eina per a crear fitxers *.jar, que és jar.exe, executada a la carpeta classes del projecte, amb la línia de comanaments:

    C:\D110src\D110ws\Modul_5\Scrolling\classes>jar.exe cvf
    Scrolling.jar .

    Es crearà el fitxer Scrolling.jar, el qual contindrà tots els fitxers de la carpeta actual (el paràmetre ".") i de les seves subcarpetes, en particular, tot el contingut de la carpeta imatges, és a dir, el fitxer bott_001.jpg.
Pràctica

Doncs, som-hi! Fem aquests canvis en el codi i fem el fitxer Scrolling.jar... I, després, vegem si tot ha funcionat bé:

  • A la carpeta classes del projecte ha d'haver aparegut el nou fitxer Scrolling.jar.

  • Obrim el fitxer Scrolling.jar amb WinZip. L'aspecte ha de ser aquest:


    El fitxer bott_001.jpg ha de figurar amb el path imatges\ i, amb el path meta-inf\, hi ha d'haver el fitxer Manifest.mf. D'aquest últim fitxer en parlarem d'aquí una mica.

  • Ara traslladem el fitxer Scrolling.jar a qualsevol altra carpeta de la nostra màquina i cridem la Màquina Virtual de Java que executi la nostra aplicació comprimida amb els seus recursos. La línia de comanaments és:

    c:\On_Sigui>java -cp Scrolling.jar Scrolling

    Explicació: cridem l'eina java.exe (la Màquina Virtual de Java) tot indicant-li que les classes són (classpath, modificador -cp) al fitxer Scrolling.jar, i que la classe principal (la que conté el mètode main!) és Scrolling.class. (l'extensió *.class s'omet)

    El resultat ha de ser aquest:

Naturalment, aquest muntatge serveix per incloure als fitxers *.jar tota mena de recursos: imatges, sons, etc. La clau és a la línia, una mica enigmàtica,

URL url=getClass().getResource("imatges/bott_001.jpg");

No entrarem ara a descriure tota la maquinària associada al mètode public final Class getClass() de la classe Object (la mare de totes les classes!). Només comentar que cal que l'URL creada per getResource s'ha d'adreçar al mateix lloc d'on ha estat carregada la classe ElMeuCanvas, és a dir, el fitxer Scrolling.jar, i no a cap carpeta del sistema, i que això ho fa el mètode getClass().(no pregunteu com!)
   
Fitxers Jar autoexecutables
   
Atenció !

El fitxer Manifest.mf que hi ha a tots els fitxers *.jar està pensat per posar-hi informacions diverses sobre els paquets, recursos i/o aplicacions que guarda. Per exemple, si tornem a obrir, mitjançant WinZip, el fitxer Scrolling.jar, i fem doble click sobre Manifest.mf, en podrem veure el contingut:

Ben poca informació! Aquest fitxer Manifest.mf és el que l'eina jar.exe crea per defecte i, com era d'esperar, no conté res rellevant. Però, si li afegim la línia

Main-Class: Scrolling

llavors conté la informació (ben rellevant, per cert!) sobre quina és la classe principal, la que conté el mètode main (l'extensió *.class s'omet). El resultat és que, ara, el nostre fitxer *.jar és autoexecutable, això és, el podem cridar directament (fent-hi clic a sobre, a Windows, per exemple) i, inmediàtament, l'aplicació s'executa.

   
Pràctica

El modus operandi és aquest:

  • Escriure el fitxer Manifest.mf amb qualsevol editor de textos ASCII (el mateix JCreator és adequat per a això), amb aquest contingut:


    i desar-lo fora de l'abast del
    paràmetre "." de jar.exe: un bon lloc és la carpeta Scrolling del projecte, al mateix lloc que els fitxers font *.java.

  • A continuació executem jar.exe a la carpeta classes del projecte, amb la línia de comanaments:

    C:\D110src\D110ws\Modul_5\Scrolling\classes>jar.exe cvfm
    Scrolling.jar ../Manifest.mf .

    Es crearà el fitxer Scrolling.jar, el qual, com abans, contindrà tots els fitxers de la carpeta actual (el paràmetre ".") i de les seves subcarpetes, és a dir, el fitxer imatges/bott_001.jpg, però com que hem afegit el modificador "m", en lloc de crear un fitxer de manifest per defecte, ara agafarà com a tal el que acabem de preparar (el paràmetre "../Manifest.mf")

  • Comprovem que tot ha anat bé. Com abans, obrim el nou fitxer M5p3_01.jar amb Winzip, mirem si hi són totes les classes i recursos i, amb doble click sobre Manifest.mf, en comprovem el contingut que ara ha de ser:


    Ara traslladem el fitxer Scrolling.jar a qualsevol altra carpeta de la nostra màquina i, després, simplement amb un doble click a sobre o, des de la línia de comanaments,

    C:\D110src\D110ws\Modul_5\Scrolling\classes>Scrolling.jar

    o, amb una drecera, ha d'engegar-se la nostra aplicació, igual que si es tractés d'un executable *.exe.
   
JCreator i Jar's
   

Els processos anteriors es poden automatitzar a JCreator. La successió

Configure -> Options -> Tools -> Create Jar File

crea l'eina personalitzada per a fer fitxers *.jar amb manifest per defecte (és a dir, sense informació rellevant). Les comandes, creades automàticament per JCreator, són aquestes:


Segur, però, que convé tenir una altra eina personalitzada per a crear fitxers *.jar amb manifest significatiu. Només cal crear una altra vegada l'eina i modificar els arguments que JCreator proposa en aquesta forma:

Llavors, només cal tenir la precaució de situar el fitxer Manifest.mf a la carpeta del projecte, per tal que jar.exe el prengui com a manifest del fitxer *.jar.

   
   
 
Amunt