IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
logo

FAQ Java GUIConsultez toutes les FAQ

Nombre d'auteurs : 37, nombre de questions : 155, dernière mise à jour : 10 octobre 2015  Ajouter une question

 

Cette FAQ a été réalisée à partir des questions fréquemment posées sur les forums de http://www.developpez.com et de l'expérience personnelle des auteurs.

Nous tenons à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose sont correctes. Les auteurs font leur maximum, mais l'erreur est humaine. Cette FAQ ne prétend pas non plus être complète. Si vous trouvez une erreur, ou que vous souhaitez nous aider en devenant rédacteur, lisez ceci.

SommaireLe dessin (13)
précédent sommaire suivant
 

Il y a principalement deux cas où un programmeur est amené à dessiner : la réalisation d'un composant graphique non-standard tel qu'un diagramme, ou la création automatique d'une image à partir de données.

Dans les deux cas, le dessin sera assuré par la classe java.awt.Graphics2D. Vous ne devez en aucun cas essayer de construire une instance de cette classe. Pour dessiner dans un composant graphique, l'instance vous est donnée en paramètre de la méthode paint(AWT) ou paintComponent(SWING). Pour le dessin dans une image, on crée un objet java.awt.Image, puis on utilise la méthode getGraphics() pour récupérer l'objet Graphics et dessiner dans l'image.

Code java : Sélectionner tout
1
2
Image img = new BufferedImage(150,52,BufferedImage.TYPE_INT_RGB); 
Graphics2D g2d = (Graphics2D)img.getGraphics();
Dessiner dans une image ne pose pas de problèmes majeurs, mais la personnalisation de composants graphiques nécessite de bien comprendre comment sont dessinés les composants par Java.

Mis à jour le 10 novembre 2002 Clement Cunin

Les solutions adoptées par SUN pour le dessin des composants sont assez complexes et un certain nombre d'optimisations sont propices à induire les débutants en erreur.

Quand un composant est-il dessiné ? Le plus important est de bien comprendre quand et pourquoi les méthodes paint(AWT) et paintComponant(SWING) sont exécutées. La première raison est une requête explicite du composant via la méthode repaint(). La deuxième raison est une requête du système, soit suite au redimensionnement de la fenêtre, soit suite au masquage du composant par une autre fenêtre du système.

La règle à toujours respecter : tout programmeur qui redéfinit la méthode paint(AWT) ou la méthode paintComponent(Swing) s'engage à redessiner l'intégralité de la surface du composant. En effet, l'objet Graphics qui est transmis au composant dessine toujours dans le même espace mémoire et cet espace n'est jamais nettoyé (pour des raisons de performances). Le programmeur du composant a donc la charge de nettoyer l'espace et de redessiner son composant. Si le composant est complexe et que son dessin est long, il est recommandé d'utiliser la technique de double-buffering pour optimiser son affichage.

Mis à jour le 10 novembre 2002 Clement Cunin

Version simple : la méthode drawString(java.lang.String,int,int) de la classe java.awt.Graphics2D correspond parfaitement à ce que l'on cherche.

Code java : Sélectionner tout
1
2
3
/** Ecriture dans une image 'img' */ 
Graphics2D g2d = (Graphics2D)img.getGraphics(); 
g2d.drawString("HelloWord",x,y);
Avec quelques raffinements : on peut améliorer un peu le procédé et choisir la police et la couleur de notre texte. En fait, la classe java.awt.Graphics2D garde un certain nombre d'attributs qui sont appliqués à toutes les opérations de dessin ; la couleur principale, la couleur secondaire (de fond), la police, la déformation. Il suffit de changer ces valeurs en utilisant la méthode appropriée.

Code java : Sélectionner tout
1
2
3
4
Graphics2D g2d = (Graphics2D)img.getGraphics(); 
g2d.setFont(new Font("Serif",Font.PLAIN,12)); 
g2d.setColor(Color.RED); 
g2d.drawString("HelloWord",x,y);
À quoi correspond (x,y) ? : les coordonnées (x,y) que l'on donne à la méthode drawString correspondent au coin inférieur gauche de la première lettre du texte. Plus précisément, la valeur y correspond à la ligne "de base" du texte. Pour les langues comme l'Arabe qui s'écrivent de droite à gauche, cette position correspond à la position du dernier caractère de la chaîne, donc de celui qui sera affiché le plus à gauche (si vous n'avez pas tout compris, faite le test ;-) ).

Mis à jour le 10 novembre 2002 Clement Cunin

Lorsque l'on dessine du texte, il est souvent utile de connaître la taille nécessaire pour l'affichage de ce texte, pour le centrer ou continuer à écrire à la ligne suivante. Il suffit pour cela de récupérer l'instance de la classe java.awt.FontMetrics du graphique dans lequel on souhaite écrire.

Code java : Sélectionner tout
1
2
3
4
Graphics2D g2d = ...; 
FontMetrics fontMetrics = g2d.getFontMetrics(); 
int longueur = fontMetrics.stringWidth("MonTexte"); 
int hauteur = fontMetrics.getHeight();

Mis à jour le 10 novembre 2002 Clement Cunin

Pas besoin de grandes phrases, un exemple suffit :

Code java : Sélectionner tout
1
2
3
4
5
6
Graphics2D g2d = ...; 
/** Lissage du texte uniquement : */ 
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,RenderingHints.VALUE_TEXT_ANTIALIAS_ON); 
  
/** Lissage du texte et des dessins */ 
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);

Mis à jour le 10 novembre 2002 Clement Cunin

La gestion de la transparence passe par l'utilisation du "canal alpha", notion bien connue des graphistes. Pour nous, la gestion de la transparence se résume à spécifier à notre graphique le pourcentage d'opacité que l'on souhaite appliquer à ce que l'on va dessiner (graphique ou texte). Une composante alpha de 0 correspond à une complète transparence, alors qu'une valeur de 1 correspond à une complète opacité.

Juste une méthode à appliquer à notre graphique :

Code java : Sélectionner tout
1
2
3
4
Graphics2D g2d = ...; 
/** 80 % de transparence */ 
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.8f )); 
g2d.drawXXX(...);

Mis à jour le 10 novembre 2002 Clement Cunin

Définir la taille du pinceau : comme toujours avec l'objet java.awt.Graphics2D, nous allons définir une nouvelle taille de pinceau qui s'appliquera à tous les traits qui seront tracés par la suite, aussi bien via la méthode drawLine(..) que via drawRect(...) ou drawShape(...).

Code java : Sélectionner tout
1
2
3
4
Graphics2D g2d = ...; 
/** Définit une épaisseur de 5 pixels */ 
g2d.setStroke(new BasicStroke( 5.0f )); 
g2d.drawXXX(...);
Le fait que la taille du pinceau soit précisée par un nombre réel peut surprendre, difficile en effet d'imaginer une ligne de 2.5 pixels. Pour comprendre, il suffit de s'imaginer le cas d'une ligne oblique, ou le cas d'un tracé avec l'anti-aliasing actif .

Définir le type de la ligne : la classe java.awt.BasicStroke, contrairement à ce que laisse penser son nom, n'est pas si basique que ça. Outre la taille du pinceau, elle permet la définition de lignes en pointillés avec éventuellement plusieurs longueurs, elle permet aussi de définir comment sont gérées les intersections des lignes d'une multiligne (shape), et plein d'autres choses encore. Je ne rentrerai donc pas dans les détails, tout est expliqué dans la documentation. Un petit exemple quand même :

Code java : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
Graphics2D g2d = ...; 
float epaisseur=3; /** taille de la ligne */ 
float[] style = {10,5}; /** les pointillés seront deux fois plus long que les blancs */ 
g2d.setStroke( new BasicStroke(  
        epaisseur, 
        BasicStroke.CAP_BUTT, 
        BasicStroke.JOIN_MITER, 
        10.0f, 
        style, 
        0 
        ));

Mis à jour le 10 novembre 2002 Clement Cunin

Les fonctions de remplissage de zone sont gérées par java.awt.Graphics2D en précisant comment colorier avant d'utiliser les méthodes fillXXX(...).

Avec un dégradé de couleur : un dégradé de couleur est calculé en fonction de deux points de référence dont on fixe la couleur, la couleur des points situés entre les deux est un dégradé linéaire.

Code java : Sélectionner tout
1
2
3
Graphics2D g2d = ...; 
g2d.setPaint(new GradientPaint(xDebut,yDebut,colDebut,xFin,yFin,colFin,cyclique); 
g2d.fillXXX(...);
Le booléen 'cyclique' permet de définir comment gérer les points au-delà des bornes.

Avec une texture :

Code java : Sélectionner tout
1
2
3
Graphics2D g2d = ...; 
g2d.setPaint(new TexturePaint(bufferedImage, new Rectangle(x,y,largeur,hauteur)); 
g2d.fillXXX(...);

Mis à jour le 10 novembre 2002 Clement Cunin

Quelques paramètres intéressants : un certain nombre de propriétés peuvent être initialisées pour indiquer vos préférences d'affichage. Voici les valeurs à mettre pour gagner en vitesse :

Code java : Sélectionner tout
1
2
3
4
5
6
7
8
/** Désactivation de l'anti-aliasing */ 
g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); 
g2D.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); 
/** Demande de rendu rapide */ 
g2D.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED); 
g2D.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_SPEED); 
g2D.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_OFF); 
g2D.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE);
Le double buffering : l'utilisation d'un double buffer est particulièrement recommandée pour l'affichage d'animations complexes ou de composants de grande taille. Voir Comment utiliser le double-buffering software ?

Mis à jour le 27 janvier 2003 Clement Cunin

L'affichage par défaut sur un composant awt, swing, ... de Java se fait à l'aide d'un simple buffer (on voit l'image se tracer). Si on commence à faire des animations un peu complexes, il apparait dès lors des problèmes de scintillements de l'image appelés clipping. Pour résoudre ce problème, on peut utiliser la méthode du double-buffering software (c'est une couche de la JVM qui s'en charge). Le double-buffering est le fait d'avoir un buffer où l'on dessine en mémoire et un buffer qui s'occupe de l'affichage. Les problèmes de rafraîchissement, saut d'image et autres bugs visuels sont ainsi éliminés.

Voici un programme très simple se servant du double-buffering software.

Code java : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
public class DoubleBufferingSoftware extends Frame{ 
   // boucle d'affichage 
   RenderingThread renderingThread = new RenderingThread(); 
   // buffer mémoire (2eme buffer) 
   Graphics buffer; 
   // image mémoire correspondant au buffer 
   Image image;  
   int x = 0; // coordonnée x de l'affichage du texte 
  
   public DoubleBufferingSoftware(){ 
      //affichage 
      setSize( 400, 400 ); 
      setVisible( true ); 
  
      // on démarre la bouche d'affichage 
      renderingThread.start(); 
  
   } 
   public void update(Graphics g){ 
      paint(g); 
   } 
   public void paint( Graphics g ){ 
     //création du buffer si il n'existe pas 
     if(buffer==null){ 
        image = createImage(400,400); 
        buffer = image.getGraphics(); 
      } 
     //on dessine sur le buffer mémoire 
      buffer.setColor( Color.white ); 
      buffer.fillRect( 0, 0, 400, 400 ); 
      buffer.setColor( Color.black ); 
      buffer.drawString( "affichage d'une ligne de texte", x, 200 ); 
      x++; 
      if(x>400) x = 0; 
      // finalement, le buffer mémoire est dessiné dans le buffer d'affichage 
      g.drawImage(image, 0, 0, this); 
   } 
   class RenderingThread extends Thread { 
     /** 
      *  Ce thread appelle le rafraîchissement de notre fenêtre  
      *  toutes les 10 millisecondes 
      */ 
      public void run(){ 
         while(true){ 
            try { 
               repaint();  
               sleep( 10 ); 
            } catch ( Exception e ) {}  
         } 
      } 
   }    
   public static void main(String[] args){new DoubleBufferingSoftware();} 
}

Mis à jour le 9 mai 2002 narkotik

Les développeurs de Sun se sont rapidement rendu compte que le double-buffering software ne suffisait pas parfois, notamment pour faire des jeux et d'autres applications graphiques très lourdes. Ils ont donc décider d'implémenter l'utilisation de la carte graphique (VRAM au lieu de la RAM) afin de diminuer une grande partie des calculs. Le page-flipping, plus communément appelé double-buffering hardware est le fait d'utiliser un pointeur vidéo pour décider quel buffer sert de mémoire et quel buffer sert d'affichage.

Principe : on créé un buffer qui va servir de buffer mémoire (celui où l'on dessine dessus), puis on créé un buffer qui va servir de buffer graphique (celui qui s'occupe d'afficher ce qu'il contient à l'écran). On dessine sur le buffer mémoire des images, des textes, des dessins, ... pendant que le buffer graphique affiche ce qu'il contient. Puis, on swap les buffers (en clair, on les inverse), le buffer mémoire devient le buffer graphique et le buffer graphique devient le buffer mémoire. On les appelle habituellement : BackBuffer (buffer mémoire) et FrontBuffer (buffer graphique).

Voici la méthode qui permet d'utiliser la mémoire vidéo de votre carte graphique (VRAM) :

Code java : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
public class DoubleBufferingHardware extends Frame{ 
   // boucle d'affichage 
   RenderingThread renderingThread = new RenderingThread();  
   // variable permettant d'utiliser la mémoire VRAM 
   BufferStrategy strategy;  
   // buffer mémoire où les images et les textes sont appliqués 
   Graphics buffer;  
   int x = 0; // coordonnée x de l'affichage du texte 
  
   public DoubleBufferingHardware(){ 
      setSize( 400, 400 ); 
      setVisible( true ); 
  
      // inhibe la méthode courante d'affichage du composant  
      setIgnoreRepaint( true );   
  
      // on crée deux buffers dans la VRAM donc c'est du double-buffering 
      createBufferStrategy( 2 );  
  
      // récupère les buffers graphiques dans la mémoire VRAM 
      strategy = getBufferStrategy();  
      buffer = strategy.getDrawGraphics(); 
      renderingThread.start();   
   } 
  
   public void graphicalRender(){ 
      buffer.setColor( Color.black );  
      buffer.fillRect( 0, 0, 400, 400 );  
      buffer.setColor( Color.white );  
      buffer.drawString( "affichage d'une ligne de texte", x, 200 ); 
      x++;  
      if ( x > 400 ) x = 0;  
      //on envoie toutes les données du buffer mémoire vers le buffer d'affichage 
      strategy.show();  
   } 
  
   class RenderingThread extends Thread{ 
     /** 
      *  Ce thread appelle le rafraîchissement de notre fenêtre  
      *  toutes les 10 millisecondes 
      */ 
      public void run(){ 
         while( true ){ 
            try { 
                // on appelle notre propre méthode de rafraîchissement 
               graphicalRender(); 
               sleep( 5 ); 
            } catch ( Exception e ) {}  
         } 
      } 
   }    
   public static void main(String[] args){new DoubleBufferingHardware();} 
}

Mis à jour le 8 septembre 2004 narkotik

La technique pour faire du triple-buffering hardware est très simple, il suffit de reprendre l'architecture pour le double-buffering hardware et de changer ceci :

Code java : Sélectionner tout
createBufferStrategy( 2 );
pour ceci :

Code java : Sélectionner tout
createBufferStrategy( 3 );
Peut-on faire mieux que du triple-buffering en mettant plus que le chiffre 3 ?

La réponse est non, car les cartes graphiques ne le gèrent pas. Si vous le tentez, soit votre carte le supporte et tournera en fait en triple-buffering, soit vous ferez planter votre programme ou aurez de gros bugs à l'affichage.

Inconvénients du triple-buffering ?

Eh bien, les cartes actuelles tournent moins bien avec le triple que le double. Résultat des courses : vous allez perdre en images par seconde lors de l'affichage. Cette diminution en performance est de l'ordre de 3, ce qui n'est pas négligeable.

Avantages du triple-buffering ?

  • Si le double-buffering ne suffisait pas à nettoyer tous les bugs d'affichage, le triple-buffering peut finir de les nettoyer. Cependant, il est vraiment très rare que le double-buffering ne suffise pas à nettoyer les bugs graphiques.
  • Dans le cas où vous faites du plein écran avec votre programme et que vous faites du double-buffering, vous avez dû remarquer que le compteur d'images par seconde est de 70-85 (bizarrement comme votre rafraîchissement d'écran sous Windows). Cela est dû au fait que le double-buffering se synchronise avec le rafraîchissement de votre écran. La solution pour passer outre cette synchronisation est le triple-buffering, celui-ci permet de casser la V-sync (synchronisation des FPS avec le rafraîchissement vertical de l'écran).

Mis à jour le 8 septembre 2004 narkotik

1. On récupère un InputStream sur le fichier TTF

Code java : Sélectionner tout
InputStream ttf;
  • depuis une servlet, le fichier TTF est dans le répertoire /fonts/ du war :


Code java : Sélectionner tout
ttf = getServletContext().getResourceAsStream("fonts/ARIALN.TTF");
  • depuis le système de fichiers :


Code java : Sélectionner tout
ttf = new FileInputStream("/aaa/bbb/ccc/ARIALN.TTF");
2. On crée une Font :

Code java : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
Font arialNarrow; 
try { 
   arialNarrow = Font.createFont(Font.TRUETYPE_FONT, ttf); 
} 
catch (Exception e) { //Une solution de rechange, au cas où... 
   arialNarrow = new Font("Arial", Font.PLAIN, 1); 
} 
finally { 
   try { 
      ttf.close(); 
   } 
   catch (Exception ignore) {} 
}
3. La Font obtenue est de taille 1. Ce qui n'est pas terrible. On utilise alors deriveFont pour en créer des dérivées. Par exemple, on obtient du arial narrow grassouillet avec :

Code java : Sélectionner tout
Font arialNarrowBold = arialNarrow.deriveFont(Font.BOLD);
Si besoin, créer une version avec ITALIC... Maintenant avec nos polices de bases, il suffit de modifier la taille.

Code java : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
BufferedImage bi = ImageIO.read("fichier.jpg"); 
Graphics2D g2d = bi.createGraphics(); 
//Antialiasing 
g2d.setRenderingHint( 
   RenderingHints.KEY_TEXT_ANTIALIASING, 
   RenderingHints.VALUE_TEXT_ANTIALIAS_ON); 
g2d.setFont(arialNarrow.deriveFont(48f)); 
//et maintenant on peut écrire en Arial Narrow de taille 48 
g2d.setFont(arialNarrowBold.deriveFont(24f)); 
//et là du Arial Narrow gras taille 24
Le petit f, c'est pour float, deriveFont accepte un int pour BOLD, ITALIC, PLAIN (qui sont des int), ou un float pour modifier la taille.

Mis à jour le 7 octobre 2015 iubito Mickael Baron

Proposer une nouvelle réponse sur la FAQ

Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour ça


Réponse à la question

Liens sous la question
précédent sommaire suivant
 

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.