3. Méthode paintComponent pour utiliser le redessinement
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.
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.
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( )); } */ |
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 paint (Graphics g) } */ |
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() |
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() |
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) public class Applet_AfficheSwing extends JApplet
public void init( ) |