Introduction à JAVA

Gestionnaires de mise en page

    Tous les systèmes d'exploitation moderne sont maintenant dotés d'interfaces graphiques. Pour assurer l'indépendance de JAVA par rapport à la plate-forme, les concepteurs aurait pu concevoir des composants graphiques spécifiques. Ils ont préféré réutiliser les composants de la machine client au moyen d'interfaces implantés dans la machine virtuelle du navigateur.  La gestion des composants graphiques est basée sur la notion de conteneurs qui sont des espaces graphiques destinés à recevoir plusieurs composants comme des boutons, des cases à cocher ... dont la mise en place graphique est fonction d'un protocole de mise en page. En effet, selon les systèmes d'exploitation, la taille et l'aspect de ces composants varient et il se pose le problème de leur positionnement.
La classe Applet dérive de la classe Panel qui est une extension de la classe abstraite Container . La classe Panel (panneau) représente des conteneurs qui sont placés dans un espace graphique existant pouvant être un autre Panel : une applet étant un Panel peut donc contenir d'autres Panels (système récursif).
     Avant d'examiner au chapitre suivant les composants graphiques gérés par JAVA, nous allons maintenant examiner les différents gestionnaires de mise en page associés aux conteneurs.

10.1 FlowLayout

C'est la mise en page par défaut (elle est utilisée quand aucun protocole n'est précisé). Dans cette mise en page "glissante", les composants graphiques sont ajoutés les uns après les autres de gauche à droite avec un saut de ligne quand il n'y a plus de place à droite. L'aspect final dépend donc de la taille de la fenêtre de l'applet.
Les trois constructeurs possibles possèdent  la syntaxe :
FlowLayout( ) , FlowLayout(int align) et   FlowLayout(int align, int dx, int dy) . dx et dy précisent l'écartement des composants en x et y.
Les constantes FlowLayout.LEFT = 0, FlowLayout.CENTER = 1 (défaut) et FlowLayout.RIGHT = 2 précisent l'alignement (align) dans une ligne.

Dans l'exemple suivant, on utilise comme composants un tableau de 4 boutons. La taille des boutons est fonction de la fonte utilisée : il est donc essentiel de définir celle-ci. La valeur de la constante pos est passée à l'applet par une balise <param>. On peut constater l'évolution de l'aspect final en fonction de la taille de l'applet. Remarquez aussi que seule la surface des composants masque la zone de dessin.

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

public class layflow extends Applet
{ Button bt[] = new Button[4];   //déclaration des boutons
   Font font= new Font("TimesRoman",0,12);
   FlowLayout fl;   //déclaration du gestionnaire
   int p;

  public void init()
   {  setBackground(Color.lightGray);
      setFont(font);
      p = Integer.parseInt(getParameter("pos")); //récupération de pos
      fl = new FlowLayout(p,15,8);         //création du gestionnaire
      setLayout(fl);     //mise en place
      for (int i=0; i<5; i++){
         bt[i]=new Button(" Bouton "+(i+1)); //création des boutons
         add(bt[i]);}} // méthode add( ) pour la mise en place des boutons

  public void paint(Graphics g)
   {  g.setFont(font);
      g.drawString("Test de flowLayout avec pos = "+p, 40, 100);
g.drawLine(0,0,size().width,size().height); }
}

 

 

 

 Dans tous les cas de mise en place simple avec peu de composants il faut utiliser ce gestionnaire .

10.2 BorderLayout

    La mise en place glissante offre peu de possibilité pour les mises en page complexes. Le protocole de spécification par les bords BorderLayout décompose le conteneur en 5 zones (précisées par les constantes North, South, East, West et Center) qui peuvent recevoir chacune un seul composant. Le constructeur BorderLayout(int dx, int dy) permet de préciser l'espace entre les composants selon x et y. Les dimensions des composants sont fonctions des dimensions du container mais leurs positions sont maintenant définies. L'exemple ci-dessous indique comment utiliser ce gestionnaire.

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

public class layborder extends Applet
{ Button bt[]=new Button[5];
   Font font= new Font("TimesRoman",0,12);
   BorderLayout fl;

  public void init()
   {  setBackground(Color.lightGray);
      setFont(font);
      fl = new BorderLayout(10,30); //création du gestionnaire
      setLayout(fl);
     for (int i=0; i<5; i++)
         bt[i]=new Button(" Bouton "+(i+1)); //création des boutons
     add("North",bt[0]);     add("South",bt[1]); //mise en place
     add("East",bt[2]);      add("West",bt[3]);
     add("Center",bt[4]);    }

   public void paint(Graphics g)
   {  g.setFont(font);
      g.drawString("Test de BorderLayout",40,110);
g.drawLine(0,0,size().width,size().height); }
}

    Avec cet exemple simpliste ce protocole semble peu intéressant puisque chaque composant graphique occupe toute la place qui lui est offerte . C'est ici que l'on peut faire intervenir la récursivité des protocoles : un conteneur est lui-même un composant graphique qui peut contenir d'autres conteneurs .
Le conteneur le mieux adapté est le panneau ( Panel ). Avec cette technique, il est possible de concevoir des mises en page d'applets assez complexes avec un code relativement simple.
Ainsi dans l'exemple suivant, nous allons placer des composants dans le haut et dans le bas de l'applet en utilisant deux objets panneaux dotés chacun de son propre gestionnaire de mise en page. Pour la mise en place des boutons dans chaque panneau, on utilise la méthode add( ) de l'instance de Panel utilisée.

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

public class layborder2 extends Applet
{  Button bt[]=new Button[5];
    Font font= new Font("TimesRoman",0,12);
    Font bold= new Font("TimesRoman",1,14);
    Panel Panor=new Panel(), Pasud=new Panel(); //création des Panels
    BorderLayout fl= new BorderLayout(10,30);    //Protocole principal

    public void init()
    { setBackground(Color.lightGray);
      setFont(font); //fonte pour les composants
      setLayout(fl);
      add("North",Panor);     add("South",Pasud); //ajout des panneaux
      Panor.setLayout(new FlowLayout(1,20,5));    //protocole du panneau supérieur
      Pasud.setLayout(new FlowLayout(2,30,10));   //protocole du panneau inférieur
      for (int i=0; i<5; i++)   //création des boutons
        bt[i]=new Button(" Bouton "+(i+1));
      for (int i=0; i<3; i++) Panor.add(bt[i]); //mise en place des boutons du haut
      for (int i=3; i<5; i++) Pasud.add(bt[i]);}

   public void paint(Graphics g)
   {  g.setFont(bold); //fonte pour l'applet
      g.drawString("Test de BorderLayout avec Panels",40,80);
      g.drawLine(0,0,size().width,size().height);}
}

 

Attention : Les Panels ainsi mis en place limitent la surface de dessin de l'applet !

 10.3 GridLayout

 Ce protocole définit une grille dont chaque cellule peut contenir un composant graphique. Les composants sont ajoutés de gauche à droite ligne par ligne. Utilisé seul ce gestionnaire n'a pas beaucoup d'intérêt. Par contre utilisé avec un protocole BorderLayout et des panneaux, il permet des mises en page intéressantes. Il existe deux constructeurs GridLayout( int lig, int col) et GridLayout( int lig, int col, int dx, int dy); lig indique le nombre de lignes de la grille et col son nombre de colonnes; dx et dy précisent l'écartement entre les composants.
Dans l'exemple suivant, on met en place dans un panneau Pasud un autre panneau PasuW doté d'un protocole Grid Layout qui va contenir 10 boutons. Il est en effet impossible de placer directement ce protocole dans Pasud car alors les composants occuperaient toute la largeur offerte. La surface en dessous du trait horizontal n'est plus disponible pour le dessin (elle est occupée par le panneau Pasud) mais peut elle peut éventuellement contenir des composants.

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

public class laygrid extends Applet
{ Button bt[]=new Button[3];
   Button bu[]=new Button[10];
   Font font= new Font("TimesRoman",0,14);
   Font bold= new Font("TimesRoman",1,12);
   Panel Panor=new Panel(), Pasud=new Panel();
   Panel PasuW=new Panel(); //container pour les boutons bu
   BorderLayout fl= new BorderLayout(10,10); 

  public void init()  
   {  setBackground(Color.lightGray);
      Panor.setFont(font);   Pasud.setFont(bold); //choix des fontes
      setLayout(fl);
      add("North",Panor);     add("South",Pasud);
      Panor.setLayout(new FlowLayout(1,20,5)); //protocoles des panneaux
      Pasud.setLayout(new FlowLayout(0,5,5));   //principaux
      Pasud.add(PasuW);     //1 panneau dans un autre
      PasuW.setLayout(new GridLayout(4,3,5,5));
//avec son gestionnaire (une grille de 4 lignes de 3 colonnes)
      for (int i=0; i<3; i++)   //création des boutons bt
         bt[i]=new Button(" Bouton "+(i+1));
      for (int i=0; i<10; i++)   //création des boutons bu
         bu[i]=new Button(" "+i+" ");
      for (int i=0; i<3; i++) Panor.add(bt[i]); //et mise en place
      for (int i=1; i<10; i++) PasuW.add(bu[i]);
      PasuW.add(bu[0]);} 

 public void paint(Graphics g)
  {  g.setFont(font);
     g.drawString("Test de GridLayout avec Panels",20,70);
     g.drawLine(0,118,320,118); //pour contrôle de la zone utile
     g.drawLine(0,size().height,size().width,0);}
}

 

 10.4 Autres protocoles

     Il existe également le gestionnaire CardLayout qui ne peut afficher qu'un seul composant à la fois (en général un panneau qui va posséder ses propres composants).Ce gestionnaire est doté de méthodes first( ), last( ), previous( ) et shows( ) qui permettent de naviguer entre les cartes. Ceci suppose la mise en place de boutons de navigation sur chaque carte.

    Enfin pour les situations complexes, existe le protocole GridBagLayout qui fonctionne avec des contraintes précisées par la classe GridBagConstraints . Dans ce gestionnaire chaque composnt est inséré dans un conteneur et on lui associe une contrainte qui précise son emplacement dans une grille, sa taille...
Ce protocole est très lourd à mettre en oeuvre et je ne le décrirai pas car il existe (à mon avis) une méthode beaucoup plus facile à mettre en application dans les applets qui est la méthode sans gestionnaire.

10.5 Mise en page sans gestionnaire

     Dans une applet, la taille de la fenêtre est imposée par les paramètres width et height de la balise <applet>. Il est donc possible de prévoir l'aspect final de l'applet dans le navigateur si la taille des composants est connue. Il existe pour les composants la méthode reshape(int ox, int oy, int large, int haut) qui permet d'imposer au composant sa position (ox, et oy) et ses dimensions (large et haut) à condition qu'un gestionnaire de mise en page ne soit pas actif .
Comme par défaut JAVA utilise un protocole FlowLayout, il faut commencer par déclarer que celui-ci est inactif au moyen de l'instruction FlowLayout fl = null . On peut ensuite placer les composants dans la fenêtre aux endroits souhaités. Cette technique suppose que la fonte utilisée pour les composants soit définie dès le départ. Comme exemple, on va reprendre le cas précédent. On peut constater que cette technique est beaucoup plus souple au niveau du positionnement des composants. On peut aussi constater qu'aucun panneau ne vient masquer la surface de l'applet.
Remarque : depuis la version 1.1, la méthode  reshape( )  a été remplacée par la méthode setBounds( ) qui possède les mêmes arguments (en fait seul le nom de la méthode a changé).

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

public class laynull extends Applet
{ Button bt[]=new Button[3];
   Button bu[]=new Button[10];
   Font font= new Font("TimesRoman",0,14);
   Font bold= new Font("TimesRoman",1,12);
   FlowLayout fl= null; //essentiel

  public void init()  
   { setBackground(Color.lightGray);
     setLayout(fl);     //essentiel
     for (int i=0; i<3; i++){
       bt[i]=new Button("Bouton "+(i+1)); //création
       add(bt[i]);     //ajout
       bt[i].setFont(font); //fonte du composant
       bt[i].reshape(20+100*i,5,80,22);} //mise en place
     setFont(bold); //fonte par défaut pour les composants à venir
     for (int i=0; i<10; i++)
       bu[i]=new Button(" "+i+" "); //création
     int k=0;
     for (int l=80; l<150; l+=30){
       for (int c=0; c<3; c++){
         k++;
         add(bu[k]); //ajout
         bu[k].reshape(100+30*c,l,25,25);}} //mise en place
     add(bu[0]);
     bu[0].reshape(130,170,25,25);}        

  public void paint(Graphics g)
   { g.setFont(font);
     g.drawString("Test sans gestionnaire",20,60);
     g.drawLine(0,size().height,size().width,0);}
}