Programmation Java Swing/Dessin de texte et effets
Le dessin d'un composant est réalisé par les méthodes paint
de la classe du composant (en Swing, la méthode void paintComponent(Graphics g)
) utilisant un contexte graphique.
Dessin de texte
[modifier | modifier le wikicode]Les méthodes de tracé de texte utilisent la couleur et la police de caractères courantes du contexte graphique. Les coordonnées spécifiées sont celles du point du début de ligne (à gauche pour le sens d'écriture de gauche à droite, ou à droite pour l'autre sens) situé au niveau de la ligne de base des caractères.
- Tracer une chaîne de caractères
g.drawString(String, int x, int y)
g.drawString(String, float x, float y)
g.drawString(AttributedCharacterIterator, int x, int y)
g.drawString(AttributedCharacterIterator, float x, float y)
- La méthode
drawString
dessine la chaîne de caractère qu'elle soit spécifiée sous la forme d'une chaînejava.lang.String
, d'un séquence de caractères avec attributsjava.text.AttributedCharacterIterator
. La classejava.awt.Graphics2D
surcharge les méthodes pour autoriser des coordonnées sous forme de nombres à virgule flottante. - Tracer un tableau de caractères
g.drawChars(char[], int offset, int length, int x, int y)
- La méthode
drawChars
dessine la chaîne de caractère représenté par le tableau de caractères spécifié. - Tracer un tableau d'octets
g.drawBytes(byte[], int offset, int length, int x, int y)
- La méthode
drawChars
dessine la chaîne de caractère représenté par le tableau de caractères spécifié.
Police de caractères
[modifier | modifier le wikicode]La police de caractères utilisée est celle définie par la méthode void setFont(Font f)
du contexte graphique.
Elle est initialisée avec celle assignée au composant.
- Voir police de caractères
Gras, italique, soulignement et barré
[modifier | modifier le wikicode]Les styles gras et italiques sont gérés par la classe java.awt.Font
(constantes PLAIN, BOLD, ITALIC, BOLD_ITALIC).
Le soulignement doit être géré par le code de dessin après ou avant avoir tracé le texte.
La classe java.awt.Font
fournit des informations pour le soulignement (distance et épaisseur de trait) via une instance de la classe java.awt.font.LineMetrics
.
Le code ci-dessous affiche un texte souligné, en exploitant ces informations et en utilisant l'objet java.awt.FontMetrics
pour mesurer le texte et obtenir la longueur de la ligne de soulignement du texte.
String texte_souligne = "Voici comment souligner le texte."
int tx = 10, ty = 20;
g.drawString(texte_souligne, tx, ty);
FontMetrics fm = g.getFontMetrics();
int tw = fm.stringWidth(texte_souligne);
LineMetrics lm = g.getFont().getLineMetrics(texte_souligne, g.getFontRenderContext());
float line_offset = lm.getUnderlineOffset();
float line_thickness = lm.getUnderlineThickness();
int ly = (int)(ty+line_offset + line_thickness /2); // Position
g.setStroke(new BasicStroke(line_thickness)); // Épaisseur
g.drawLine(tx, ly, tx+tw, ly);
Le style barré utilise le même principe en exploitant les informations retournées par les méthodes getStrikethroughOffset()
et getStrikethroughThickness()
.
Dans le code précédent, il suffit de remplacer les valeurs affectées aux variables line_offset
et line_thickness
:
float line_offset = lm.getStrikethroughOffset();
float line_thickness = lm.getStrikethroughThickness();
Les styles souligné et barré ne sont pas gérés directement par la classe java.awt.Font
car il s'agit d'éléments graphiques (lignes) séparés du texte, pouvant avoir une couleur différente du texte, ou une épaisseur différente de celle indiquée par la classe java.awt.font.LineMetrics
.
Exemple : Texte en dégradé de couleurs
[modifier | modifier le wikicode]La méthode de remplissage est représentée par une instance de la classe java.awt.Paint
.
L'instance par défaut remplit les formes avec une couleur de manière unie.
Il existe d'autres classes de remplissage dont celles permettant de peindre une forme en dégradé de couleurs.
Le tracé de texte est en fait un remplissage et il est dont possible d'utiliser un dégradé de couleurs.
Le code ci-dessous affiche une ligne de texte en dégradé de couleurs (voir image ci-dessus).
package org.wikibooks.fr.test;
import java.awt.*;
import java.util.*;
import javax.swing.*;
/**
* Test affichage en dégradé d'un texte.
* @author fr.wikibooks.org
*/
public class TestPaint extends JComponent
{
public static void main(String[] args)
{
JFrame f = new JFrame("Test de rendu avec Java Swing");
f.setSize(800, 300);
f.add(new TestPaint());
f.setVisible(true);
}
/** Police de caractères utilisée. */
private static final Font F_TEXTE = new Font("Dialog", Font.BOLD, 80);
/** Couleurs utilisées. */
private static final Color
C_BG = Color.BLACK,
// Orange -> Rouge
C_FG_TEXT_1 = new Color(220,190,0),
C_FG_TEXT_2 = new Color(250,50,0);
// Bleu -> Vert
// C_FG_TEXT_1 = new Color(40,120,240),
// C_FG_TEXT_2 = new Color(80,210,170);
/** Options pour améliorer l'affichage. */
private HashMap<RenderingHints.Key, Object> hm_hints = new HashMap<RenderingHints.Key, Object>();
private TestPaint()
{
hm_hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
hm_hints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
hm_hints.put(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
hm_hints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
hm_hints.put(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE);
hm_hints.put(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
setBackground(C_BG);
}
@Override
protected void paintComponent(Graphics gg)
{
Graphics2D g = (Graphics2D) gg;
g.setRenderingHints(hm_hints);
// Selon les dimensions du composant
Dimension d = getSize();
g.setColor(getBackground());
g.fillRect(0, 0, d.width, d.height);
g.setFont(F_TEXTE);
FontMetrics fm = g.getFontMetrics();
// Hauteurs des caractères (au dessus et en dessous de la ligne de base)
int ha = fm.getMaxAscent(), hb = fm.getMaxDescent();
// Texte à afficher :
String s = "fr.wikibooks.org";
// Largeur du texte, et calcul de la position centrée du texte
int ws = fm.stringWidth(s),
x = (d.width-ws)/2, y = (d.height+ha-hb)/2;
// Dégradé linéaire vertical débutant à 5 pixels du haut et se terminant à 5 pixels du bas du texte.
GradientPaint gp = new GradientPaint(new Point(x,y-ha+5), C_FG_TEXT_1, new Point(x,y+hb-5), C_FG_TEXT_2);
Paint p = g.getPaint(); // Pour restaurer
g.setPaint(gp);
g.drawString(s, x, y);
g.setPaint(p); // Restauration
}
}
Utiliser la forme des caractères
[modifier | modifier le wikicode]Pour un affichage de texte plus évolué, il est possible d'exploiter la forme des caractères.
La forme des caractères est représentée par une instance de la classe java.awt.font.GlyphVector
.
Cette classe possède des méthodes retournant des instances de la classe java.awt.Shape
qui peuvent donc être manipulées, et notamment utilisées avec les méthodes draw
et fill
du contexte graphique.
Le texte tel que montré par l'image ci-dessus est dessiné par le code ci-dessous et reprend la première partie du code de la section précédente, en remplaçant l'affichage du texte par la récupération de la forme des caractères.
Celle-ci est obtenue en appelant la méthode createGlyphVector
de la police de caractère, en lui passant le contexte de rendu et le texte.
Cette forme des caractères est ensuite utilisée :
- pour obtenir les rectangles autour du caractère w (en position 3),
- pour tracer le contour des glyphes du texte en pointillé.
package org.wikibooks.fr.test;
import java.awt.*;
import java.awt.font.*;
import java.awt.geom.*;
import java.util.*;
import javax.swing.*;
/**
* Test affichage en dégradé d'un texte.
* @author fr.wikibooks.org
*/
public class TestPaint extends JComponent
{
public static void main(String[] args)
{
JFrame f = new JFrame("Test de rendu avec Java Swing");
f.setSize(800, 300);
f.add(new TestPaint());
f.setVisible(true);
}
/** Police de caractères utilisée. */
private static final Font F_TEXTE = new Font("Dialog", Font.BOLD, 80);
/** Couleurs utilisées. */
private static final Color
C_BG = Color.BLACK,
C_LIGNE = new Color(210,160,40),
C_RECT_1 = new Color(20,120,240),
C_RECT_2 = new Color(0,64,128),
C_TEXTE = Color.WHITE;
/** Options pour améliorer l'affichage. */
private HashMap<RenderingHints.Key, Object> hm_hints = new HashMap<RenderingHints.Key, Object>();
private TestPaint()
{
hm_hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
hm_hints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
hm_hints.put(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
hm_hints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
hm_hints.put(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE);
hm_hints.put(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
setBackground(C_BG);
}
@Override
protected void paintComponent(Graphics gg)
{
Graphics2D g = (Graphics2D) gg;
g.setRenderingHints(hm_hints);
// Selon les dimensions du composant
Dimension d = getSize();
g.setColor(getBackground());
g.fillRect(0, 0, d.width, d.height);
g.setFont(F_TEXTE);
FontMetrics fm = g.getFontMetrics();
// Hauteurs des caractères (au dessus et en dessous de la ligne de base)
int ha = fm.getMaxAscent(), hb = fm.getMaxDescent();
// Texte à afficher :
String s = "fr.wikibooks.org";
// Largeur du texte, et calcul de la position centrée du texte
int ws = fm.stringWidth(s),
x = (d.width-ws)/2, y = (d.height+ha-hb)/2;
// Ensemble de glyphes du texte à partir de la police de caractères
GlyphVector gv = F_TEXTE.createGlyphVector(g.getFontRenderContext(), s);
Shape
sh_title = gv.getOutline(), // Contour des caractères
// Caractère en position 3 (w) :
sh_w_ext = gv.getGlyphLogicalBounds(3), // - Rectangle de toute la zone du caractère
sh_w = gv.getGlyphVisualBounds(3); // - Rectangle resserré sur le caractère
g.setColor(C_LIGNE);
g.fillRect(x-100, y-14, ws+200, 16);
AffineTransform at = g.getTransform();
g.translate(x, y);
g.setColor(C_RECT_1);
g.fill(sh_w_ext);
g.setColor(C_RECT_2);
g.fill(sh_w);
// Tracé en pointillé, épaisseur 3 pixels
Stroke sk = new BasicStroke(3, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 5.0f, new float[]{ 10f, 5f }, 5f);
Stroke st = g.getStroke();
g.setStroke(sk);
g.setColor(C_TEXTE);
g.draw(sh_title);
g.setStroke(st); // Restaurer
g.setTransform(at); // Restaurer
// Équivalent de g.drawString :
//g.drawGlyphVector(gv, x, y);
}
}