Enrera
Mòdul 5
Iniciació a la programació en Java
  Pràctica
1
2
3
4
   
Exercicis
Exercicis
 
 
  Organitzant una finestra
   

Aquesta pràctica té com a objectiu aprendre a programar la disposició dels controls en una finestra, és a dir, a programar la disposició dels elements que formaran la interfície gràfica d'usuari GUI (Graphics User Interface) mitjançant la qual els usuaris de les nostres aplicacions poden interactuar amb elles, fer-les servir, vaja.

  • Es discuteix la noció, propia de Java, de layout manager i se'n presenten tres exemples i el seu ús. També s'ensenya com combinar diversos layout managers per tal d'obtenir estructures més complexes.
  • Es presenta i s'ensenya l'ús del control més senzill: el label (etiqueta amb text) i, de passada, es fa una introducció al maneig del color.

  • Finalment, s'introdueixen tres controls més, els botons i els dos associats a textos editables, encara que es reserva el treball sobre les seves funcionalitats per a pràctiques posteriors.
   
Desenvolupament de la pràctica
   

La finestra base o finestra arrel que hem après a construir a la pràctica anterior ja té tota la funcionalitat necessària per tal de rebre i disposar els controls que han de constituir l'interfície gràfica, la GUI, de les nostres aplicacions.

La classe java.awt.Frame deriva de java.awt.Container, és a dir, és un contenidor (container) cosa que vol dir que està preparada per emmagatzemar components (derivats de java.awt.Component) i, a més, incorpora una estructura (layout) la qual s'encarregarà de gestionar la disposició d'aquests components a la pantalla.

   
Els "layouts"
   
Atenció !

"Write once, run anywhere". Ja hem dit que una aplicació Java ha de ser independent del maquinari. I això té molta importància aquí: la GUI de les nostres aplicacions no pot pressuposar res,per exemple,sobre el tamany o la resolució en píxels de la pantalla del ordinador en la qual s'executaran. Per tant, no es una bona cosa pensar: "Vull un botó de 90 x 40 a la posició 145, 230" i, de fet, les classes de l'AWT ja s'encarreguen d'impedir tan com poden que el programador se'n surti si pensa les coses així...

Cal aprendre a pensar en termes de "layouts". Un layout és un esquema general de disposició a la pantalla dels components d'un contenidor. El layout manager s'encarrega automàticament de donar les dimensions adequades als components i d'alinear-los segons les disponibilitats.

L'AWT ens proporciona aquests layout managers:

  • java.awt.BorderLayout

  • java.awt.CardLayout

  • java.awt.FlowLayout

  • java.awt.GridBagLayout

  • java.awt.GridLayout

dels quals us invitem a veure'n la documentació ara mateix.

Conclusió: Si volem disposar elements per a una GUI, aquests elements han de ser derivats de la classe java.awt.Component, o d'alguna de les seves classes filles (tots els controls ho són!). El lloc per disposar-los ha de ser una classe derivada de java.awt.Container (o d'alguna de les seves classes filles) provista del layout manager que més s'adigui als desitjos del programador.

Per a usos corrents, el contenidor adequat és gairebé sempre la classe java.awt.Panel.

   
Comencem!
   
Pràctica

Començarem posant uns quants labels (etiquetes de text) distribuïts per la nostra finestra. Iniciem un nou projecte, Layouts01, (definiu-lo com a "Basic Java Application"), i després de comentar la línia package myprojects.Layouts01;, modifiqueu el codi que JCreator ha posat en el fitxer Layouts01.java. Les parts a modificar estan en color groc clar:

/*
* @(#)Layouts01.java 1.0 02/09/13
*
* 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.Layouts01;
import java.awt.*;
import java.awt.event.*;

class Layouts01 extends Frame {

    public Layouts01() {
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                dispose();
                System.exit(0);
            }
        });
    }

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

        mainFrame.setTitle("Cinc Labels en BorderLayout");

        Label label_1=new Label("Això és el primer 'Label'");
        label_1.setAlignment(Label.CENTER);

        Label label_2=new Label("Això és el segon 'Label'");
        label_2.setBackground(Color.YELLOW);
        label_2.setAlignment(Label.CENTER);

        Label label_3=new Label("Això és el tercer 'Label'");
        label_3.setBackground(Color.BLUE);
        label_3.setForeground(Color.WHITE);
        label_3.setAlignment(Label.CENTER);

        Label label_4=new Label("Això és el quart 'Label'");
        label_4.setBackground(Color.CYAN);
        label_4.setAlignment(Label.CENTER);

        Label label_5=new Label("Això és el cinquè 'Label'");
        label_5.setBackground(Color.BLACK);
        label_5.setForeground(Color.PINK);
        label_5.setAlignment(Label.CENTER);

        mainFrame.add(label_1,BorderLayout.NORTH);
        mainFrame.add(label_2,BorderLayout.SOUTH);
        mainFrame.add(label_3,BorderLayout.EAST);
        mainFrame.add(label_4,BorderLayout.WEST);
        mainFrame.add(label_5,BorderLayout.CENTER);

        mainFrame.setVisible(true);
    }
}
   
  El resultat ha de ser aquest:
   
 
   
  Vegem què hem fet:
 
Atenció !
  • Hem construït cinc instàncies del control java.awt.Label, que és el control més senzill que hi ha: la seva única funcionalitat és la de mostrar un text. Consulteu-ne la documentació per veure'n els mètodes constructors. En els cinc casos, hem fet servir el mètode constructor public Label(String text) i, com ja es pot suposar, el paràmetre text és el text que el label ha de mostrar-nos.

  • Si, com en el cas de label_1 (el nom "label_1" és arbitrari, clar!) no fem cap altra especificació, el color del fons (background), el dels caràcters del text (foreground) i la font són els del contenidor on hem posat el component. Al nostre cas, el Frame (la finestra) era de fons blanc i si hi haguéssim escrit alguna cosa, el text hagués estat negre. Aquesta és doncs, la presentació de label_1. En canvi, als altres labels hi hem fet modificacions mitjançant els mètodes public void setForeground(Color color) i public void setBackground(Color color), de la classe mare de Label, java.awt.Component.

  • A Java tot són classes i no podia ésser d'altra manera amb el color! Examineu ara la documentació de la classe java.awt.Color. Si volem obtenir un determinat color podem acudir directament a les variables static

    Color.BLACK
    Color.BLUE
    Color.CYAN
    Color.DARK_GRAY
    Color.GRAY
    Color.GREEN
    Color.LIGHT_GRAY
    Color.MAGENTA
    Color.ORANGE
    Color.PINK
    Color.RED
    Color.WHITE
    Color.YELLOW


    o bé, construir el color RGB amb algun dels mètodes constructors de java.awt.Color. Per exemple, podeu substituir la línia

    label_3.setBackground(Color.BLUE);

    per

    label_3.setBackground(new Color(0,0,255));

    i, tot canviant els paràmetres, veure'n els resultats.

  • Si per causa de l'actuació del layout manager algun label és més ample que el text que mostra, llavors és important determinar-ne l'alineament. Tenim disponibles les variables static de java.awt.Label següents:

    Label.CENTER
    Label.LEFT
    Label.RIGHT

    i el mètode public void setAlignment(int alignment). Podeu fer proves, canviar els alineaments dels labels 1, 2 4 i 5 i pensar perquè en uns casos hi ha canvis i en d'altres no..

  • Finalment, els cinc labels s'han disposat així dins del contenidor (la finestra) precisament perquè, per defecte, java.awt.Frame porta incorporat el layout manager java.awt.BorderLayout. Aquest layout manager admet fins a cinc components i els disposa així:


    i, si volem afegir els nostres components, els nostres labels, cal fer servir el mètode public void add(Component component,String position). El paràmetre position és una de les cinc variables static:

    BorderLayout.NORTH
    BorderLayout.SOUTH
    BorderLayout.EAST
    BorderLayout.WEST
    BorderLayout.CENTER


  • Per veure el funcionalent de java.awt.BorderLayout, retallem ara una mica el text dels labels i deixem-los així:

    Label label_1=new Label("N");

    Label label_2=new Label("S");

    Label label_3=new Label("E");

    Label label_4=new Label("W");

    Label label_5=new Label("C");


    El resultat és:


    i ens mostren que:

    • les dimensions del label s'adapten a les necessitats: un label té les dimensions mínimes per tal que hi càpiga el text que ha de mostrar

    • java.awt.BorderLayout ignora les dimensions horitzontals dels components situats a "north" i "south", però en respecta les verticals.

    • java.awt.BorderLayout ignora les dimensions verticals dels components situats a "east" i "west", però en respecta les horitzontals.

    • java.awt.BorderLayout ignora tant les dimensions horitzontals com les verticals del component situat a "center".

    Encara ens en podem convèncer més si modifiquem les dimensions de la finestra, canviant els paràmetres a la línia

    mainFrame.setSize(400, 400);
  Més layouts:
 
Atenció !

java.awt.BorderLayout és el layout manager per defecte de java.awt.Frame, però podem canviar-lo. Inmediatament després de la línia

Layouts01 mainFrame = new Layouts01();

insertem la línia:

mainFrame.setLayout(new FlowLayout());

la qual determina que ara mainFrame té una instància de java.awt.FlowLayout com a layout manager. També cal que canviem les línies

        mainFrame.add(label_1,BorderLayout.NORTH);
        mainFrame.add(label_2,BorderLayout.SOUTH);
        mainFrame.add(label_3,BorderLayout.EAST);
        mainFrame.add(label_4,BorderLayout.WEST);
        mainFrame.add(label_5,BorderLayout.CENTER);

per les línies:

        mainFrame.add(label_1);
        mainFrame.add(label_2);
        mainFrame.add(label_3);
        mainFrame.add(label_4);
        mainFrame.add(label_5);

i si volem ser coherents, canviem el títol de la finestra:

mainFrame.setTitle("Cinc Labels en FlowLayout");

Per veure'n bé l'efecte, fem que els respectius textos dels labels tinguin longituds variades, per exemple:

Label label_1=new Label("Aquest era el Label del Nord");

Label label_2=new Label("I aquest el del Sud");

Label label_3=new Label("Era del Est");

Label label_4=new Label("Del Oest");

Label label_5=new Label("Era el Label del Centre");


El resultat és:

   
Com funciona el FlowLayout?
   
Atenció !
  • Les dimensions, tant horitzontals com verticals, dels components es respecten.

  • Els components es disposen cadascun a continuació de l'anterior, de la mateixa maneraque les paraules sobre un text. Quan s'esgota l'espai horitzontal, s'inicia una nova línia.
   
Un altre layout:
   
Atenció !

Finalment, discutirem el layout manager java.awt.GridLayout. Només cal modificar la línia

mainFrame.setLayout(new FlowLayout());

amb:

mainFrame.setLayout(new GridLayout(3,2));

(i la de mainFrame.setTitle( ... ))

Obtenim:

Si ara canviem new GridLayout(3,2) per new GridLayout(4,2) obtenim:

tot mostrant que:

  • el layout manager  java.awt.GridLayout disposa els components en una matriu rectangular de files files i columnes columnes. El mètode constructor és: public GridLayout(int files,int columnes).

  • No es respecta cap de les dimensions dels components. Les dimensions es forcen per tal que totes les cel·les de la matriu siguin iguals
   
Combinant layouts...
   
Atenció !

Naturalment, aquests layout managers es poden combinar per donar lloc a estructures més complexes. La classe java.awt.Panel és filla de java.awt.Container, la qual és filla de java.awt.Component. Per tant, java.awt.Panel és un contenidor (pot admetre components) i també és un component i, per tant, pot ser incorporat a un contenidor. Això vol dir que podem prendre una instància de java.awt.Panel, dotar-la del layout manager que ens interessi (per defecte és java.awt.FlowLayout) posar-hi els components que calgui i posar-ho tot plegat com a component a la nostra finestra, que ja tindrà el seu propi layout manager.

   
Un exemple de combinació:
   
Pràctica Nou projecte, Layouts02, (definiu-lo també com a "Basic Java Application"): Després de comentar la línia package myprojects.Layouts02;, modifiqueu el codi que JCreator ha posat en el fitxer Layouts02.java. Les parts a modificar estan en color groc clar:
   
 

/*
* @(#)Layouts02.java 1.0 02/09/15
*
* 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.Layouts02;
import java.awt.*;
import java.awt.event.*;

class Layouts02 extends Frame {

    public Layouts02() {
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                dispose();
                System.exit(0);
            }
        });
    }

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

        mainFrame.setLayout(new BorderLayout());
        mainFrame.setTitle("Combinació de Layouts");

        Panel panel=new Panel();
        panel.setLayout(new GridLayout(1,5));

        TextField text_N=new TextField("Nord: hi pots escriure "+
                                       "aquí...");
        mainFrame.add(text_N,BorderLayout.NORTH);

        Label label_E=new Label("Est",Label.CENTER);
        label_E.setBackground(Color.YELLOW);
        label_E.setForeground(Color.BLACK);
        mainFrame.add(label_E,BorderLayout.EAST);

        Label label_W=new Label("Oest",Label.CENTER);
        label_W.setBackground(Color.PINK);
        label_W.setForeground(Color.BLACK);
        mainFrame.add(label_W,BorderLayout.WEST);

        TextArea text_C=new TextArea("Centre:\n tambe hi pots "+
                                     "escriure aquí...");
        mainFrame.add(text_C,BorderLayout.CENTER);

        Label label_S_1=new Label("Sud 1",Label.CENTER);
        label_S_1.setBackground(Color.MAGENTA);
        label_S_1.setForeground(Color.YELLOW);
        panel.add(label_S_1);

        Button boto_S_2=new Button("Sud 2");
        panel.add(boto_S_2);

        Label label_S_3=new Label("Sud 3",Label.CENTER);
        label_S_3.setBackground(Color.GREEN);
        label_S_3.setForeground(Color.WHITE);
        panel.add(label_S_3);

        Button boto_S_4=new Button("Sud 4");
        boto_S_4.setBackground(Color.RED);
        boto_S_4.setForeground(Color.BLACK);
        panel.add(boto_S_4);

        Label label_S_5=new Label("Sud 5",Label.CENTER);
        label_S_5.setBackground(Color.LIGHT_GRAY);
        label_S_5.setForeground(Color.BLACK);
        panel.add(label_S_5);

        mainFrame.add(panel,BorderLayout.SOUTH);

        mainFrame.setVisible(true);
    }
}
   
  amb aquest resultat:

   
Què hi ha de nou?
   
Atenció !
  • A la construcció dels labels hem fet servir ara un altre mètode constructor, en el qual s'hi pot especificar directament l'alineament (vegeu la documentació de java.awt.Label).

  • Per tal de trencar la monotonia i anticipar algunes coses, hem incorporat nous controls a part dels ja coneguts labels:

    • java.awt.TextField, que ocupa la posició "north". Serveix per a introduir i editar textos curts d'una sola línia.

    • java.awt.TextArea, que ocupa la posició "center". Serveix per a introduir i editar textos multilínia.

    • java.awt.Button. Dos exemplars al panel de la posició "south".

      Lla funcionalitat dels quals es discutirà més endavant. Observeu-ne els mètodes constructors i compareu-los amb les documentacions respectives.

  • Els components que van a les posicions "north", "center", "east" i "west" s'han afegit a mainFrame en la mateixa forma que ho hem fet abans a Layouts01.

  • El component que va a la posició "south" és una instància de java.awt.Panel, provist del layout manager java.awt.GridLayout, d'una fila i cinc columnes.

  • Els cinc components que van a la posició "south" s'han afegit al contenidor panel, el qual s'afegeix després a mainFrame a la posició "south"
Pràctica
Ara podeu experimentar amb més components i més contenidors i fer estructures més complexes sobre aquest mainFrame...
   
   
 
Amunt