I. Qu'est-ce qu'un java.awt.Paint ?▲
Un java.awt.Paint est la description de la façon dont on va remplir une forme quelconque.
Il est applicable en Java2D via Graphics2D et sa méthode setPaint. Cette méthode définit ainsi la manière dont les méthodes fill… doivent remplir la surface. Il s'agit du motif de remplissage, mais pas du crayon qui permet ce remplissage, chose qui est gérée par setStroke.
Il existe trois java.awt.Paint tout prêts en standard dans Java : couleur unie, basé sur une image et dégradé à partir de deux couleurs.
Nous allons construire un Paint faisant des rayures verticales
II. Ce qu'il faut savoir pour comprendre▲
II-A. La représentation des couleurs▲
Comme le Paint manipule les couleurs pixel par pixel sous la forme d'entiers, il est nécessaire de comprendre comment les couleurs sont représentées.
Les couleurs sont faites des quatre composantes, l'alpha, le rouge, le vert et le bleu.
Ces quantités vont de 0 à 255.
Le rouge, le vert et le bleu sont les quantités de rouge de vert et de bleu. L'alpha est le degré de transparence 0 totalement transparent, 255 totalement opaque. La classe Color reprend ces paramètres.
Une couleur est en fait un int. On peut récupérer cet entier de la classe Color grâce à getRGB(). Cet entier est codé sur quatre octets, un octet par composante de couleur. Pour récupérer les différentes composantes, on fait :
alpha
=
(couleur>
>
24
)&
0xFF
;rouge
=
(couleur>
>
16
)&
0xFF
;vert
=
(couleur>
>
8
)&
0xFF
;bleu
=
couleur&
0xFF
;
Pour rassembler les composantes en une couleur :
couleur =
(alpha &
0xFF
) <
<
24
|
(rouge &
0xFF
) <
<
16
|
(vert &
0xFF
) <
<
8
|
(bleu &
0xFF
);
Les images, les composants graphiques, peuvent être vus comme des tableaux de pixels, chaque pixel étant un entier représentant une couleur. Ce tableau est en une seule dimension, bien qu'il représente des données en deux dimensions. Si largeur est la largeur de la vue 2D alors, les largeur premiers pixels représentent la première ligne, les largeur suivants la seconde ligne… Ce qui fait que pour accéder au pixel (x, y), on fait : pixels[x+y*largeur] si « pixels » est le tableau de pixels.
II-B. La façon dont le java.awt.Paint est dessiné à l'écran▲
Pour remplir une forme d'un Paint donné, il faut calculer le rectangle minimal englobant cette forme. Avec ce rectangle est construit un PaintContext.
Ensuite le rectangle est découpé en petits rectangles, et chacun de ces petits rectangles est rempli grâce à la méthode getRaster. En fait, le Raster fourni est sauvegardé pour que le dessin puisse se faire un peu plus tard, mais on peut faire comme si on dessinait immédiatement, car on dessine sur le Raster, qui lui est recopié à l'écran.
Comme le rectangle englobant est fourni au départ on le sauvegardera pour le calcul du dessin des petits rectangles.
III. Les étapes à travers un exemple▲
III-A. Description de l'exemple▲
Nous allons construire un Paint pour faire des rayures verticales, en plus des informations obligatoires, comme le ColorModel et le rectangle englobant, le PaintContexte va recevoir les paramètres de rayures.
Paramètres de rayures : une couleur de fond, une couleur de rayure, l'écart entre les rayures et l'épaisseur des rayures.
L'algorithme de dessin va donc ressembler à :
couleurFond
<
-
couleur du fondcouleurRayure
<
-
couleur des rayuresecart
<
-
écart entre les rayuresepaisseur
<
-
épaisseur des rayuresplace
<
-
écart+
épaisseurlargeur
<
-
largeur du rectangle englobantlarg
<
-
largeur du petit rectanglehaut
<
-
hauteur du petit rectanglexr
<
-
gauche du rectangle englobantxp
<
-
gauche du petit rectanglex
<
-
xp-
xrraster
<
-
créer raster de taille larg x hautPour
(i=
0
; i<
larg; i+
+
){
couleur
<
-
couleurFondSi
((i+
x)%
place>=
écart){
couleur
<
-
couleurRayure}
Pour
(j=
0
; j<
haut; j+
+
){
raster
(i, j)<
-
couleur}
}
Nous allons maintenant pouvoir créer le PaintContext, puis le Paint.
III-B. Contruire le java.awt.PaintContext▲
import
java.awt.Color;import
java.awt.PaintContext;import
java.awt.Rectangle;import
java.awt.image.ColorModel;import
java.awt.image.Raster;import
sun.awt.image.IntegerComponentRaster;/**
*
Version
:
1
.
0
*
@author
JHelp
*
@version
1
.
0
*/
public
class
PeintureRayeeVerticaleContexteimplements
PaintContext{
//
Modèle
de
couleur
utilisé
private
ColorModel modeleCouleur;//
Rectangle
englobant
la
forme
à
peindre
private
Rectangle rectangleEnglobant;//
Couleurs
de
fond
et
de
rayure
private
int
couleurFond, couleurRayure;//
Écart
entre
les
rayures
//
Épaisseur
des
rayures
//
Place
que
prend
le
motif
private
int
ecart, epaisseur, place;/**
*
Construit
le
PaintContext
pour
peindre
des
rayures
verticales
*
@param
modeleCouleur
Modèle
de
couleurs
utilisé
*
@param
rectangleEnglobant
Rectangle
englobant
la
forme
*
@param
couleurFond
Couleur
du
fond
*
@param
couleurRayure
Couleur
des
rayures
*
@param
ecart
Écart
entre
les
rayures
*
@param
epaisseur
Épaisseur
des
rayures
*/
public
PeintureRayeeVerticaleContexte
(ColorModel modeleCouleur,Rectangle rectangleEnglobant,
Color couleurFond,
Color couleurRayure,
int
ecart,int
epaisseur){
this
.modeleCouleur=
modeleCouleur;this
.rectangleEnglobant=
rectangleEnglobant;this
.couleurFond=
couleurFond.getRGB
();this
.couleurRayure=
couleurRayure.getRGB
();this
.ecart=
ecart;this
.epaisseur=
epaisseur;this
.place=
this
.ecart+
this
.epaisseur;}
/**
*
Détruit
le
contexte
,
ici
rien
n
'
est
à
détruire
*
@see
java
.
awt
.
PaintContext
#
dispose
(
)
*/
public
void
dispose
(){
}
/**
*
Modèle
des
couleurs
*
@return
Modèle
des
couleurs
*
@see
java
.
awt
.
PaintContext
#
getColorModel
(
)
*/
public
ColorModelgetColorModel
(){
return
this
.modeleCouleur;}
/**
*
Construit
le
Raster
et
dessine
dessus
*
@param
x
Abscisse
du
coin
haut
gauche
du
petit
rectangle
*
@param
y
Ordonnée
du
coin
haut
gauche
du
petit
rectangle
*
@param
largeur
Largeur
du
petit
rectangle
*
@param
hauteur
Hauteur
du
petit
rectangle
*
@return
Le
Raster
peint
*
@see
java
.
awt
.
PaintContext
#
getRaster
(
int
,
int
,
int
,
int
)
*/
public
RastergetRaster
(int
x,int
y,int
largeur,int
hauteur){
//
Construit
le
raster
de
la
taille
du
petit
rectangle
IntegerComponentRaster raster
=
(IntegerComponentRaster)this
.modeleCouleur.createCompatibleWritableRaster
(largeur, hauteur);//
Calcule
l'abscisse
du
petit
rectangle
relativement
à
l'englobant
int
xx=
x-
this
.rectangleEnglobant.x;//
Offsett
de
démarrage
de
peinture
(En
général
ça
vaut
0)
int
off=
raster.getDataOffset
(0
);//
Largeur
de
peinture
(En
général
c'est
exactement
la
largeur
du
petit
rectangle)
int
longueur=
raster.getScanlineStride
();//
Pixels
du
Raster
à
peindre
int
[] pixels=
raster.getDataStorage
();//
Pour
chaque
colonne
du
rectangle
à
faire
for
(int
i=
0
; i<
largeur; i+
+
){
//
Calcul
de
la
couleur
selon
l'abscisse
du
point
int
couleur=
this
.couleurFond;if
((i+
xx)%
this
.place>=
this
.ecart){
couleur
=
this
.couleurRayure;}
//
Sur
toute
la
colonne
de
l'abscisse
en
cours
colorier
de
la
même
couleur
for
(int
j=
0
; j<
hauteur; j+
+
){
//
Le
tableau
de
pixels
est
d'une
seule
dimension,
bien
que
représentant
une
image
à
deux
dimensions.
//
En
fait
la
première
ligne
est
sur
les
longueur
premiers
éléments,
//
la
seconde
sur
les
longueur
suivants
//
...
//
off
est
le
point
de
départ
sur
le
tableau
pixels[j
*
longueur+
i+
off]=
couleur;}
}
return
raster;}
}
III-C. Construire le java.awt.Paint▲
import
java.awt.Color;import
java.awt.Paint;import
java.awt.PaintContext;import
java.awt.Rectangle;import
java.awt.RenderingHints;import
java.awt.geom.AffineTransform;import
java.awt.geom.Rectangle2D;import
java.awt.image.ColorModel;/**
*
@author
JHelp
*
@version
1
.
0
*/
public
class
PeintureRayeeVerticaleimplements
Paint{
//
Couleur
de
fond
et
de
rayures
private
Color couleurFond, couleurRayure;//
Écart
entre
les
rayures
//
Épaisseur
des
rayures
private
int
ecart, epaisseur;/**
*
Construit
le
Paint
pour
peindre
des
rayures
verticales
*
@param
couleurFond
Couleur
du
fond
*
@param
couleurRayure
Couleur
des
rayures
*
@param
ecart
Écart
entre
les
rayures
*
@param
epaisseur
Épaisseur
des
rayures
*/
public
PeintureRayeeVerticale
(Color couleurFond, Color couleurRayure,int
ecart,int
epaisseur){
if
(couleurFond=
=
null
){
throw
new
NullPointerException
("
La
couleur
de
fond
ne
doit
pas
être
);
}
if
(couleurRayure=
=
null
){
throw
new
NullPointerException
("
La
couleur
des
rayures
ne
doit
pas
être
);
}
if
(ecart<
0
){
throw
new
IllegalArgumentException
("
L'écart
entre
les
rayures
doit
être
positif
ou
nul
"
);}
if
(epaisseur<
0
){
throw
new
IllegalArgumentException
("
L'épaisseur
des
rayures
doit
être
positive
ou
nulle
"
);}
this
.couleurFond=
couleurFond;this
.couleurRayure=
couleurRayure;this
.ecart=
ecart;this
.epaisseur=
epaisseur;}
/**
*
Crée
le
PaintContext
,
cette
méthode
est
appelée
par
la
fonction
qui
peint
*
@param
cm
Modèle
de
couleur
*
@param
deviceBounds
Rectangle
englobant
de
la
forme
à
peindre
*
@param
userBounds
Rectangle
relatif
de
la
forme
à
peindre
?
(
Pas
sur
)
*
@param
xform
Transformation
que
subit
la
peinture
.
Ici
ne
sert
pas
,
mais
*
on
peut
l
'
inclure
en
paramètre
du
PaintContext
,
ce
qui
par
la
suite
*
permet
de
l
'
utiliser
pour
transformer
la
forme
obtenue
*
@param
hints
?
Je
ne
sais
pas
encore
?
*
@return
Le
PaintContext
*
@see
java
.
awt
.
Paint
#
createContext
(
java
.
awt
.
image
.
ColorModel
,
java
.
awt
.
Rectangle
,
*
java
.
awt
.
geom
.
Rectangle2D
,
java
.
awt
.
geom
.
AffineTransform
,
java
.
awt
.
RenderingHints
)
*/
public
PaintContextcreateContext
(ColorModel cm,Rectangle deviceBounds,
Rectangle2D userBounds,
AffineTransform xform,
RenderingHints hints)
{
return
new
PeintureRayeeVerticaleContexte
(cm, deviceBounds,this
.couleurFond,this
.couleurRayure,this
.ecart,this
.epaisseur);}
/**
*
Indique
le
mode
de
transparence
,
cela
sert
à
la
méthode
qui
peint
pour
optimiser
quand
c
'
est
totalement
opaque
*
@return
Le
mode
de
transparence
*
@see
java
.
awt
.
Transparency
#
getTransparency
(
)
*/
public
int
getTransparency
(){
//
Si
l'une
des
couleurs
a
un
facteur
de
transparence
non
maximum,
alors
il
//
faut
gérer
la
transparence,
sinon
c'est
inutile,
car
c'est
totalement
opaque
if
(this
.couleurFond.getAlpha
()<
255
|
|
this
.couleurRayure.getAlpha
()<
255
){
return
Paint.TRANSLUCENT;}
return
Paint.OPAQUE;}
}
III-D. Exemple d'utilisation▲
import
java.awt.BorderLayout;import
java.awt.Color;import
java.awt.Dimension;import
java.awt.Graphics;import
java.awt.Graphics2D;import
java.awt.image.BufferedImage;import
javax.swing.JFrame;import
javax.swing.JLabel;import
javax.swing.UIManager;/**
*
@author
JHelp
*
@version
1
.
0
*/
public
class
Testextends
JFrame{
/**
*
Dessin
*
@author
JHelp
*
@version
1
.
0
*/
public
class
Dessinextends
JLabel{
//
Image
portant
le
dessin
private
BufferedImage image=
new
BufferedImage
(200
,200
, BufferedImage.TYPE_INT_ARGB);/**
*
Construit
le
composant
portant
l
'
image
*/
public
Dessin
(){
this
.setPreferredSize
(new
Dimension
(200
,200
));//
Dessine
l'image
Graphics2D g2
=
this
.image.createGraphics
();;g2.
setPaint
(new
PeintureRayeeVerticale
(Color.BLACK, Color.CYAN,10
,3
));g2.
fillOval
(20
,50
,100
,50
);g2.
setPaint
(new
PeintureRayeeVerticale
(new
Color
(255
,255
,255
,127
), Color.RED,5
,1
));g2.
fillOval
(50
,20
,50
,100
);}
/**
*
Dessine
le
composant
*
@param
g
Environement
graphique
*
@see
javax
.
swing
.
JComponent
#
paintComponent
(
java
.
awt
.
Graphics
)
*/
protected
void
paintComponent
(Graphics g){
g.
drawImage
(this
.image, (this
.getWidth
()-
200
)/
2
, (this
.getHeight
()-
200
)/
2
,this
);}
}
/**
*
Construit
le
test
*/
public
Test
(){
super
("
Test
-
Paint
"
);this
.setDefaultCloseOperation
(JFrame.EXIT_ON_CLOSE);this
.getContentPane
().setLayout
(new
BorderLayout
());this
.getContentPane
().add
(new
Dessin
(), BorderLayout.CENTER);this
.pack
();}
/**
*
Lance
le
test
*/
public
static
void
main
(String[] args){
Test test
=
new
Test
();test.
setVisible
(true
);}
}
