2.5.Afficher des composants, redessiner
    une Applet Awt - Swing



    Plan de ce chapitre:   ...........retour au plan général

    1. Avec la bibliothèque Awt
     

    2. Avec la bibliothèque Swing
     

    2.1 Les 4 couches superposées d'affichage d'une JApplet
    2.2 Les deux seules couches utilisées
    2.3 la méthode paint de l'applet redessine l'applet seulement
     


    3. Méthode paintComponent pour utiliser le redessinement
     

      3.1 Exemple d'ajout d'un bouton à une fenêtre
    3.2 Mettez un JPanel dans votre applet



    Objectif : Comparatif de programmation d'affichage et de redessinement de composants visuels sur une applet Awt et sur une applet Swing. On souhaite redessiner les composants visuels déposés sur une applet lorsqu'ils ont été masqués (par une autre fenêtre) et qu'il nous faut les réafficher.
     
     

    1. Avec la bibliothèque Awt
     

       
    En Awt on dépose directement des composants visuels avec la méthode add sur une applet de classe Applet. En fait le dessin du composant déposé s'effectue sur l'objet Canvas de l'applet ( Canvas est une classe dérivée de Component destinée à traiter des dessins) :

    La méthode public void paint( ) d'une applet Awt est automatiquement appelée par l'applet pour dessiner l'ensemble des graphiques de l'applet. Lorsque l'applet doit être redessinée (la première fois et à chaque fois que l'applet est masquée totalement ou partiellement) c'est la méthode paint qui est automatiquement appelée. Nous avons déjà appris que si nous voulions effectuer des dessins spécifiques ou des actions particulières lors du redessinement de l'applet nous devions redéfinir la méthode paint de l'applet.

    Lorsque l'on dépose un composant sur une applet de classe Applet, le parent du composant est l'applet elle-même.
     
     

    2. Avec la bibliothèque Swing

    Le travail est plus complexe avec Swing, en effet le JApplet comme le JFrame, est un conteneur de composants visuels qui dispose de 4 niveaux de superposition d'objets à qui est déléguée la gestion du contenu du JApplet.
     

    2.1 Les 4 couches superposées d'affichage d'une JApplet

    La racine JRootPane, les couches JLayredPane et GlassPane servent essentiellement à l'organisation des menus et du look and feel. Nous rappellons que seule la couche ContentPane doit être utilisée par le développeur pour écrire ses programmes.

    Tout ce que l'on dépose sur une JApplet doit en fait l'être sur son ContentPane qui est une instance de la classe Container. C'est pourquoi dans les exemples qui sont proposés vous trouvez l'instruction :
     

    this.getContentPane( ).add(....)

    2.2 Les deux seules couches utilisées

    Parmi ces couches nous n'en utiliserons que deux :

    Colorons l'applet en jaune, son contentPane en vert et déposons un JButton "OK" sur l'applet (sur son contentPane) :
    public class Applet_Swing extends JApplet
    {
     Container contentPane = getContentPane();
     void Ecrire ( )
     {
      System.out.println("couleur this =" + this.getBackground( ).toString( ));
      System.out.println("couleur contentPane =" + contentPane.getBackground( ).toString( ));
      System.out.println("couleur parent du contentPane =" + contentPane.getParent( ).getBackground( ).toString( ));

     }
     public void init( )
     {
       JButton bouton = new JButton("OK");
       bouton.setBounds(100,50,80,30);
       contentPane.setLayout(null);
       contentPane.add(bouton);
       contentPane.setBackground(Color.green);
       this.setBackground(Color.yellow);
       Ecrire( );
     }
    }
    /* les valeurs des couleurs en RGB :
    yellow = 255,255,0 <--- JApplet
    green = 0,255,0   <--- contentPane de JApplet

    */


     
    Résultat visuel de l'applet : Résultat des écritures de l'applet :
    couleur this = java.awt.Color[r=255,g=255,b=0] yellow

    couleur contentPane = java.awt.Color[r=0,g=255,b=0] green

    couleur parent du contentPane = java.awt.Color[r=255,g=255,b=0] yellow

    Nous remarquons que nous voyons le bouton déposé et positionné sur le contentPane et le fond vert du contentPane, mais pas le fond de l'applet (this.setBackground(Color.yellow); représente la coloration du fond de l'applet elle-même).
     
     

    2.3 la méthode paint de l'applet redessine l'applet seulement

    Essayons d'agir comme avec une applet Awt en redéfinissant la méthode paint (JApplet dérivant de Applet possède la méthode paint) sans mettre de code dans le corps de cette méthode, afin de voir quel travail effectue la méthode paint :
     
    public class Applet_Swing extends JApplet
    {
     Container contentPane = getContentPane();
     void Ecrire ( )
     {
      System.out.println("couleur this =" + this.getBackground( ).toString( ));
      System.out.println("couleur contentPane =" + contentPane.getBackground( ).toString( ));
      System.out.println("couleur parent du contentPane =" + contentPane.getParent( ).getBackground( ).toString( ));

     }
     public void init( )
     {
       JButton bouton = new JButton("OK");
       bouton.setBounds(100,50,80,30);
       contentPane.setLayout(null);
       contentPane.add(bouton);
       contentPane.setBackground(Color.green);
       this.setBackground(Color.yellow);
       Ecrire( );
     }

     public void  paint (Graphics g)
     { // redéfinition de la méthode : pas d'action nouvelle
     }

    }
    /* les valeurs des couleurs en RGB :
    yellow = 255,255,0 <--- JApplet
    green = 0,255,0   <--- contentPane de JApplet

    */

    Résultats obtenus lors de l'exécution de l'applet :

    Nous nous rendons compte que cette fois-ci, le fond du contentPane vert n'a pas été affiché, mais que c'est le fond jaune de l'applet elle-même qui l'est. Le bouton OK n'est pas visible bien qu'il existe sur l'applet.
     
     

    Nous masquons entièrement l'applet par une fiche, puis nous le démasquons : le bouton OK est alors redessiné par l'applet mais pas par la méthode paint. Si plutot nous faisons passer la souris dans la zone supposée du bouton OK c'est le bouton qui se redessine lui-même mais pas la méthode paint

    En effet après avoir fait apparaître le bouton masquons partiellement l'applet avec une autre fenêtre, puis démasquons l'applet en rendant la fenêtre de l'applet active.

    Nous voyons que l'applet a bien été rafraîchie mais que l'image du bouton ne l'a pas été, donc la méthode paint redéfinie redessine l'applet, mais n'a pas redessiné le bouton OK qui est déposé sur le contentPane.
    Conclusion n°1
    La méthode paint redéfinie redessine l'applet, mais ne redessine pas les objets du contentPane.

     

    2.4 Variations :  appel à la méthode paint de la super classe

    1°) Sachant qu'une applet de classe Applet de Awt  se redessine avec tous ses composants :

    java.awt.Container
                  |
                  +--java.awt.Panel
                        |
                        +--java.applet.Applet
     

    2°) Sachant que JApplet de Swing est une classe fille de Applet , nous nous proposons alors de faire appel à la méthode paint de l'ancêtre (la super classe) qui est la classe Applet de Awt. Dans ce cas nous forcerons l'applet Swing à réagir comme une applet Awt :

    java.applet.Applet
                              |
                              +--javax.swing.JApplet
     
     public void  paint (Graphics g)
     { // redéfinition de la méthode : on appelle la méthode de l'ancêtre
           super.paint ( g );
     }

    Nouveau résultat d'exécution :

    Nous remarquons que l'appel à la méthode paint de la super classe provoque un affichage correct, le masquage et le démasquage fonctionnent correctement aussi. C'est cette solution que nous avons adoptée dans les exercices corrigés.

    Problème potentiel d'instabilité de Java
    Les concepteurs de Swing déconseillent cette démarche car la surcharge de la méthode paint de l'applet (en fait de la classe Container) pourrait interférer dans certains cas avec la méthode paint du JComponent qui surcharge elle-même déjà la méthode paint de la classe Container.

     
     
     

    3. Méthode paintComponent pour utiliser le redessinement
     

    3.1 Généralités pour un composant

    Il est conseillé en général d'utiliser systématiquement la méthode paintComponent de chaque composant qui est appelée automatiquement dès que l'applet est redessinée. En fait chaque composant reçoit une notification de redessinement et la méthode paintComponent de chaque composant est exécutée. Si en outre nous voulons effectuer des actions spécifiques pendant le redessinement d'un composant, nous devons alors surcharger la méthode paintComponent de ce composant.
     
     

    3.2 Mettez un JPanel dans votre applet

    Le composant de base qui encapsule tous les autres composants d'une applet JApplet est son contentPane. Etant donné que contentPane est un objet nous ne pouvons donc pas surcharger de méthode du contentPane (on peut surcharger une méthode dans une classe ) nous créons une nouvelle classe  héritant des JPanel  :
     
    class JPanelApplet extends JPanel
     {
          JPanelApplet( ) // constructeur
          {
             setBackground(Color.white); // le fond est blanc
          }
    }

    Nous allons rajouter une couche supplémentaire sur l'applet avec un nouvel objet instancié à partir de cette nouvelle classe  héritant des JPanel dont nous surchargerons la méthode paintComponent (puisqu'elle est invoquée automatiquement par l'applet). Nous déposerons ce JPanel sur le contentPane de l'applet.
     
    class JPanelApplet extends JPanel
     {
       JPanelApplet( ) // constructeur
      {
             setBackground(Color.white); // le fond est blanc
       }
      public void paintComponent (Graphics g)
      { // le redessinement est traité ici
         super.paintComponent(g);
         g.drawString("Information dessinée sur le fond graphique", 10, 40);
       }
    }

    Nous instancions un objet panneau de cette classe et l'ajoutons au contentPane de l'applet :
    public class Applet_AfficheSwing extends JApplet
    {
      JPanelApplet panneau;

      public void init()
     {
       Container contentPane = getContentPane( );
       panneau = new JPanelApplet( );
       contentPane.add(panneau);
       contentPane.setBackground(Color.green);
       this.setBackground(Color.yellow);
      }
    }

    Nous déposerons tous nos composants sur ce JPanel,  ceci permettra aussi de transformer plus facilement des applications encapsulées dans un JPanel qui peut être identiquement déposé sur un JFrame vers une applet Swing..
     
    public class Applet_AfficheSwing extends JApplet
    {
      JPanelApplet panneau;

      public void init()
     {
       Container contentPane = getContentPane( );
       panneau = new JPanelApplet( );
       contentPane.add(panneau);
       contentPane.setBackground(Color.green);
       this.setBackground(Color.yellow);
       JButton bouton = new JButton("OK");
       bouton.setBounds(100,50,80,30);
       panneau.setLayout(null);
       panneau.add(bouton);
      }
    }

    Voici le résultat de l'exécution de l'applet ainsi construite:

     

    Conclusion

    Toute action à effectuer lors du redessinement de l'applet pourra donc être intégrée dans la méthode surchargée paintComponent de la classe JPanelApplet, le code minimal d'une applet Swing ressemblera alors à ceci :
     
    class JPanelApplet extends JPanel
     {
       JPanelApplet( ) // constructeur
      {
             ..........
       }

     public void paintComponent (Graphics g)
      { // le redessinement est traité ici
         super.paintComponent(g);
         //..... vos actions spécifiques lors du redessinement
       }
    }

    public class Applet_AfficheSwing extends JApplet
    {
      JPanelApplet panneau;

      public void init( )
     {
       Container contentPane = getContentPane( );
       panneau = new JPanelApplet( );
       contentPane.add(panneau);
       ................... // les composants sont ajoutés à l'objet "panneau"
      }
    }


     
     

    Remonter