Le double buffering

Accueil

Ce 4 février 2013, nous avons examiné des fonctions graphiques plus élaborées.
Il s’agit de construire une image hors de la vue de l’utilisateur, pour ne l'afficher ensuite qu’une fois terminée.

Cette technique s’appelle le double-buffering.

Tout comme un JPanel, une image possède un contexte graphique, qui peut être obtenu par monImage.getGraphics();

L’instruction complète est Graphics imG = monImage.getGraphics();

Donc l’image peut aussi bien recevoir des instructions graphiques (drawLine, fillOval; drawPolygon, …)
qu’être elle-même dessinée sur le contexte graphique d’un JPanel, ou d’une autre image.

Intérêts du double-buffering

Eviter le scintillement

La première étape d’une animation consiste à dessiner un rectangle d'effacement de dimensions identiques à la zone de dessin (à l’image).
Ce rectangle détermine la couleur de fond.

Ensuite, le logiciel calcule la position des différents éléments graphiques à afficher, et les dessine un par un.
Si ces calculs sont complexes, l’utilisateur a le temps de suivre l’élaboration du dessin.

Une fois la composition du dessin achevée, le logiciel attend un délai d’affichage, puis recommence le processus.
Le rectangle d’effacement supprime instantanément tous les graphismes de la vue de l’utilisateur, puis le logiciel recommence, à les dessiner un par un.

Cette phase noire est assez pénible pour l’utilisateur qui suit l’animation.

La solution consiste à construire le graphique hors de la vue de l’utilisateur, dans une image off en mémoire.
Pour ne l’afficher instantanément (drawImage) qu’après son achèvement complet.
En redessinant l’image suivante exactement au même endroit que la précédente, l’utilisateur ne percevra que les différences. Il aura l’illusion d’un mouvement, d’une animation.

Dessiner hors-champ

L’image de double-buffering peut être plus petite que le JPanel qui l’accueille.
D’autre part, il n’est pas interdit de dessiner au-delà des limites de l’image.

Les éléments en-dehors de l’image seront tout simplement ignorés.

Puisqu’un exemple vaut mieux qu’un long discours, l’arrivée de la planète Mars en bas à droite du panorama est un exemple dynamique de graphisme recadré par double-buffering.

Le panorama illustre plusieurs exemples de recadrage :

Affichage multiple

Une image ne doit être composée qu’une seule fois, mais peut être affichée plusieurs fois,
en plusieurs endroits du JPanel ou sur plusieurs JPanels différents.

Voici le code source de l’application graphique que nous avons construite ensemble ce 4 février 2013.

 

La classe principale, elle construit la JFrame Source
La fenêtre (JFrame) Source
Un premier panneau de dessin animé par un thread, qui crée un dessin animé dans une image de double-buffering Source

Nous avons ensuite enlevé ce panneau de la JFrame pour le remplacer par un autre illustrant la classe Graphics2D,
avec des dégradés d’une couleur à l’autre.
Les points d’origine des dégradés sont pilotés par la souris (illustration d’un MouseEvent)

Pour rappel :

  • Le clic gauche définit l’origine de la couleur 1
  • Le clic droit définit l’origine de la couleur 2
  • Vous définissez les couleurs depuis le menu déroulant
  • La case à cocher Cyclique vous permet de définir le caractère cyclique ou non du dégradé.

Source

 

Attention, les coordonnées du clic souris doivent bien être recueillies dans l’objet qui en a besoin.

Au cours du labo, j'ai commis un bug consistant à programmer un écouteur de souris (MouseListener) dans la JFrame,
pour ensuite passer les paramètres (x, y) du clic recueilli en arguments au JPanel qui avait besoin des points d’origine des dégradés.

Par acquis de conscience, j’ai programmé, lors du dessin, un carré et un rond aux deux points d'origine.

A ma surprise, ils se sont affichés plus bas, verticalement sous la souris, d’une hauteur correspondant à la barre de menus.

En fait, c’est tout à fait normal :

La solution fut de déménager l’écouteur de souris de la JFrame vers le JPanel.

Et voici l’application en Java Web Start

Enjoy !