Interfaces Graphiques - membres

Transcription

Interfaces Graphiques - membres
Interfaces Graphiques
Dessiner avec JAVA
Contexte Graphique
Rafraîchissement
Java2D
© Philippe GENOUD
GUI
Mai 2005
UJF
1
bibliographie
bibliographie
The JFC Tutorial: A guide to constructing GUI
Kathy Walrath, Mary Campione
http://java.sun.com/docs/books/tutorial/uiswing
Java Tutorial Specialized trails : Trail: 2D Graphics
Deborah Adair, Jennifer Ball and Monica Pawlan
http://java.sun.com/docs/books/tutorial/2d
Java 2D Graphics
Jonathan Knudsen, Ed. O'Reilly
Java 2D API Graphics
Vincent J. Hardy, Java Series, Prentice Hall
© Philippe GENOUD
UJF
Mai 2005
2
1
GUI
Adaptateurs
Adaptateurs d’événements
d’événements
Dessin
Dessin des
des segments
segments de
de droite
droite
Gestion des événements souris
Déplacement de la souris sur
la zone de dessin met à jour
les coordonnées du curseur
dans la barre d’état
MOUSE_MOVED, MOUSE_DRAGGED
Appuyer sur un bouton de la
souris (MOUSE_PRESSED) définit
le début d ’une droite
Relacher le bouton de la
souris (MOUSE_RELEASED)
définit la fin de la droite
•type d ’événement MouseEvent
•source : zone de dessin
•interface d ’écoute : MouseListener
•récepteur : zone de dessin
Comme pour la fermeture de la
fenêtre seule deux des méthodes
de l ’interface nous intéressent
< interface >
MouseListener
void mouseClicked(MouseEvent)
void mouseEntered(MouseEvent)
void mouseExited(MouseEvent)
void mousePressed(MouseEvent)
void mouseReleased(MouseEvent)
© Philippe GENOUD
GUI
Mai 2005
UJF
3
Adaptateurs
Adaptateurs d’événements
d’événements
Dessin
Dessin des
des segments
segments de
de droite
droite
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class ZoneDessin extends JPanel
implements MouseMotionListener {
private BarreEtat be;
public ZoneDessin(BarreEtat be) {
setBackground(Color.white);
setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
this.be = be;
addMouseMotionListener(this);
}
addMouseListener(new GestionnaireClic(this));
Pour ne pas avoir à définir des
méthodes inutiles possibilité
d’utiliser un adaptateur
d’événements : MouseAdapter
import java.awt.event.*;
public class GestionnaireClic
extends MouseAdapter {
ZoneGraphique zone;
public void mouseMoved(MouseEvent e) {
be.afficheCoord(e.getX(),e.getY());
}
public GestionnaireClic(ZoneGraphique z)
{
zone = z;
}
public void mouseDragged(MouseEvent e) {
be.afficheCoord(e.getX(),e.getY());
}
public void mousePressed(MouseEvent e)
{
zone.initieDroite(e.getX(),e.getY());
}
public void initieDroite(int x, int y) {
be.afficheMessage("Relacher pour dessiner la droite");
// on complétera ensuite
}
public void termineDroite(int x, int y) {
be.afficheMessage("Cliquer pour initier une droite");
// on complétera ensuite
}
public void mouseReleased(MouseEvent e)
{
zone.termineDroite(e.getX(),e.getY());
}
} // ZoneGraphique
}
© Philippe GENOUD
UJF
Mai 2005
4
2
GUI
Adaptateurs
Adaptateurs d’événements
d’événements
Dessin
Dessin des
des segments
segments de
de droite
droite
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
Avec une classe interne
(inner classe) anonyme
public class ZoneDessin extends Jpanel implements MouseMotionListener {
private BarreEtat be;
public ZoneDessin(BarreEtat be) {
setBackground(Color.white);
setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
this.be = be;
addMouseMotionListener(this);
addMouseListener(
new MouseAdapter() {
public void mousePressed(MouseEvent e)
{
initieDroite(e.getX(),e.getY());
}
L’instance de la classe
anonyme a implicitement
accès à l ’instance de la
classe externe qui (c.a.d.
l’instance) a provoqué sa
création :
en conséquence elle a
accès aux membres de la
classe externe
public void mouseReleased(MouseEvent e)
{
termineDroite(e.getX(),e.getY());
}
}
);
}
public void initieDroite(int x, int y) {
be.afficheMessage(« Relacher pour dessiner la droite »);
// on complétera ensuite
}
public void termineDroite(int x, int y) {
be.afficheMessage(« Cliquer pour initier une droite »);
// on complétera ensuite
}
...
} // ZoneGraphique
© Philippe GENOUD
GUI
UJF
ZoneDessin.this
Mai 2005
5
Dessiner
Dessiner avec
avec Java
Java
Dessin
Dessin des
des segments
segments de
de droite
droite
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class ZoneDessin extends Jpanel implements MouseMotionListener {
private BarreEtat be;
public ZoneDessin(BarreEtat be) {
setBackground(Color.white);
setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
this.be = be;
addMouseMotionListener(this);
addMouseListener(
new MouseAdapter() {
public void mousePressed(MouseEvent e)
{
initieDroite(e.getX(),e.getY());
}
public void mouseReleased(MouseEvent e)
{
termineDroite(e.getX(),e.getY());
}
}
);
}
public void initieDroite(int x, int y) {
be.afficheMessage(« Relacher pour dessiner la droite »);
// on complétera ensuite
// on complétera ensuite
}
public void termineDroite(int x, int y) {
be.afficheMessage(« Cliquer pour initier une droite »);
//
// on
on complétera
complétera ensuite
ensuite
}
...
} // ZoneGraphique
© Philippe GENOUD
UJF
Comment
dessiner avec
Java ?
Mai 2005
6
3
GUI
Contexte
Contexte Graphique
Graphique
Ici le support du dessin représenté par une instance de la classe JPpanel
avec java.awt dans la plupart des cas il s’agit d ’une instance de la classe
Canvas
Il faut des outils pour dessiner :
primitives géométriques (droites, cercles, rectangles …)
gestion des attributs de tracé (couleur du trait, couleur de remplissage, polices
de caractères …)
Ces outils sont représentés en Java par la classe Graphics du package
java.awt
Object
Graphics
The Graphics class is the abstract base class for all graphics contexts that allow an application to draw onto
components that are realized on various devices, as well as onto off-screen images.
A Graphics object encapsulates state information needed for the basic rendering operations that Java supports.
Classe abstraite : les instances de cette classe sont fournies à la demande par le système
d’exploitation qui grâce à la machine virtuelle instanciera une sous-classe de Graphics
spécifique à la plate-forme utilisée
méthodes de Graphics
pour dessiner des formes
© Philippe GENOUD
GUI
Mai 2005
UJF
7
Dessiner
Dessiner avec
avec Java
Java
Dessin
Dessin des
des segments
segments de
de droite
droite
Repère graphique
X
Appuyer sur un bouton de la
souris (MOUSE_PRESSED) définit
le début d ’une droite
Relacher le bouton de la
souris (MOUSE_RELEASED)
définit la fin de la droite
y
•type d’événement MouseEvent
Coordonnées position de
la souris
x
150
?
x
250
?
y
50
?
y
110
?
Exprimées dans le repère de la
source de l’événement : le JPanel
© Philippe GENOUD
UJF
Mai 2005
8
4
GUI
Dessiner
Dessiner avec
avec Java
Java
Dessin
Dessin des
des segments
segments de
de droite
droite
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class ZoneDessin extends Jpanel implements MouseMotionListener {
lorsque le bouton de
la souris est pressé :
mémoriser le début
d’un nouveau
segment
private BarreEtat be;
int xInit, yInit;
public ZoneDessin(BarreEtat be) {
setBackground(Color.white);
setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
this.be = be;
addMouseMotionListener(this);
addMouseListener( new MouseAdapter() { ... } );
}
public void initieDroite(int x, int y) {
be.afficheMessage(« Relacher pour dessiner la droite »);
xInit = x;
yInit = y;
lorsque le bouton de
la souris est relaché :
}
public void termineDroite(int x, int y) {
be.afficheMessage(« Cliquer pour initier une droite »);
1) récupérer le
contexte graphique
associé au JPanel
Graphics g = this.getGraphics();
g.drawLine(xInit,yInit,x,y);
}
...
} // ZoneDessin
2) Utiliser l’objet
Graphics pour
effectuer le dessin
© Philippe GENOUD
GUI
UJF
Mai 2005
9
Dessiner
Dessiner en
en Java
Java
«« rafraichissement
rafraichissement »» du
du dessin
dessin
Problème de réaffichage après que la fenêtre ait été masquée,
redimensionnée…
GO
1
Zône non rafraichie
2
Application seule ne peut pas
décider du moment où elle doit
être rafraîchie
Le système ne prend pas en
charge seul le rafraîchissement
avertit uniquement
l’application qu’elle doit se
redessiner (en lui indiquant
quel est son rectangle
invalide)
à la charge de celle-ci de
se redessiner
© Philippe GENOUD
3
UJF
Mai 2005
10
5
GUI
Affichage
Affichage d'un
d'un composant
composant
Quand un composant est-il affiché ?
à la demande du système (System triggered painting)
quand le composant est rendu visible pour la première fois
quand le composant a été recouvert puis découvert
appel de la méthode paint(Graphics g) du composant
à la demande de l'application (Application triggered painting)
quand le programme ou un composant Swing détermine que le composant doit
être réaffiché
en interne dans les Swing (changement d'un texte, d'une couleur...)
dans votre propre programme en faisant une demande explicite de
réaffichage
appel de la méthode repaint() du composant
– place une demande d'affichage dans la file d'attente des événements
– le thread de gestion des événements se chargera d'appeler la méthode paint()
ne jamais appeler paint() directement, toujours utiliser repaint()
© Philippe GENOUD
GUI
Mai 2005
UJF
11
Affichage
Affichage d'un
d'un composant
composant
Que fait la méthode paint() ?
1) le fond
2) affichage spécifique
3) bordure
(background)
(custom painting)
(border)
(children)
(si opaque)
(si présent)
(si présent)
(si présent)
paintComponent(Graphics g)
• dessine le composant lui-même
• déjà implémentée pour les composants
standards (fenêtres, boutons, …)
4) les fils
paintBorder(Graphics g)
Dessine bordures
ajoutées au composant
(en utilisant setBorder)
paintChildren(Graphics g)
Ne pas appeler
directement cette
méthode ni la redéfinir.
• doit être redéfinie (overriden) pour créer
vos propres composants
© Philippe GENOUD
UJF
Mai 2005
12
6
GUI
Affichage
Affichage d'un
d'un composant
composant
un composant se dessine avant chacun des composants qu'il contient
d'une interface Swing s'effectue récursivement en descendant la
hiérarchie des containers
affichage
composant
qui affiche
du texte
bouton 1
bouton 2
ordre d'affichage
© Philippe GENOUD
GUI
UJF
fenêtre
contentPane
panneau gauche
composant texte
Mai 2005
panneau droite
bouton1
bouton2
13
Affichage
Affichage d'un
d'un composant
composant
Pour résumer
Chaque composant graphique possède une méthode qui définit comment il
doit se dessiner
Evidemment pour les composants standards (fenêtres, boutons, …) il est
inutile de définir comment ils doivent s’afficher
public void paint(Graphics g) pour les composants awt
public void paintComponent(Graphics g) pour les composants swings
une fenêtre affichera son cadre et son fond puis affichera tout les composants
qu’elle contient
un conteneur affichera son fond puis affichera récursivement tous les composants
qu'il contient
…
Mais dès que l’application gère ses propres graphiques via un contexte
graphique (objet Graphics) elle devra se soucier de leur rafraichissement et
redéfinir paintComponent
© Philippe GENOUD
UJF
Mai 2005
14
7
GUI
Dessiner
Dessiner en
en Java
Java
«« rafraichissement
rafraichissement »» du
du dessin
dessin
Redessiner les segments de droite disparus
il faut stocker les informations pour afficher à nouveau tous les segments
déjà dessinés
classes SegmentDroite et Dessin
Java 2 (1.4)
import java.util.*;
import java.awt.*;
public class Dessin {
private List lesDroites = new ArrayList();
import java.awt.*;
public class SegmentDroite
{
private int xInit, yInit, xFin, yFin;
private Color couleur;
public SegmentDroite(int xi, int yi, int xf,
int yf, Color c) {
xInit = xi; yInit = yi;
xFin = xf; yFin = yf;
couleur = c;
}
public void dessineToi(Graphics g)
{
g.setColor(couleur);
g.drawLine(xInit, yInit,xFin,yFin);
}
}
© Philippe GENOUD
GUI
public void ajouterDroite(SegmentDroite d) {
lesDroites.add(d);
}
public void dessineToi(Graphics g) {
for (Iterator it=lesDroites.iterator(); it.hasNext();)
{
SegmentDroite d = (SegmentDroite) it.next();
d.dessineToi(g);
}
}
public void efface() {
lesDroites.clear();
}
public void defaire() {
if (! lesDroites.isEmpty()){
lesDroites.remove(lesDroites.size()-1);
}
}
} // Dessin
Mai 2005
UJF
15
Dessiner
Dessiner en
en Java
Java
«« rafraichissement
rafraichissement »» du
du dessin
dessin
Redessiner les segments de droite disparus
il faut stocker les informations pour afficher à nouveau tous les segments
déjà dessinés
classes SegmentDroite et Dessin
Java 5
2 (1.5)
(1.4)
import java.util.*;
import java.awt.*;
import java.awt.*;
public class SegmentDroite
{
private int xInit, yInit, xFin, yFin;
private Color couleur;
public SegmentDroite(int xi, int yi, int xf,
int yf, Color c) {
xInit = xi; yInit = yi;
xFin = xf; yFin = yf;
couleur = c;
}
public void dessineToi(Graphics g)
{
g.setColor(couleur);
g.drawLine(xInit, yInit,xFin,yFin);
}
}
© Philippe GENOUD
public class Dessin {
private
lesDroites = newlesDroites
ArrayList();
private List
List<SegmentDroite>
=
new ArrayList<SegmentDroite>();
public void ajouterDroite(SegmentDroite d) {
lesDroites.add(d);
}
public void dessineToi(Graphics g) {
for (Iterator it=lesDroites.iterator(); it.hasNext();)
for (SegmetDroit d : lesDroites) {
{
d.dessineToi(g);
SegmentDroite d = (SegmentDroite) it.next();
}
d.dessineToi(g);
}
}
public void efface() {
lesDroites.clear();
}
public void defaire() {
if (! lesDroites.isEmpty()){
lesDroites.remove(lesDroites.size()-1);
}
}
} // Dessin
Mai 2005
UJF
16
8
GUI
Dessiner
Dessiner en
en Java
Java
«« rafraichissement
rafraichissement »» du
du dessin
dessin
Redessiner les segments de droite disparus
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class ZoneDessin extends Jpanel
implements MouseMotionListener {
private BarreEtat be;
private int xInit, yInit;
Rajout d’un objet dessin
pour mémoriser les
segments dessinés
private Dessin dessin = new Dessin();
public ZoneDessin(BarreEtat be) {
...
}
Mémorisation des
nouveaux objets tracés
public void initieDroite(int x, int y) {
be.afficheMessage(« Relacher pour dessiner la droite »);
xInit = x; yInit =y;
}
public void termineDroite(int x, int y) {
be.afficheMessage(« Cliquer pour initier une droite »);
Graphics g = this.getGraphics();
g.drawLine(xInit,yInit,x,y);
SegmentDroite
droite = new
SegmentDroite(x,y,xInit,yInit,couleurCourante);
dessin.ajouterDroite(droite);
droite.dessineToi(g);
}
...
public void paintComponent(Graphics g) {
super.paintComponent(g);
dessin.dessineToi(g);
}
Redéfinition de la méthode
paintComponent pour
gérer le réaffichage
permet de dessiner l'arrière plan
sinon affichage du fond doit être fait
explicitement ou setOpaque(false) doit
être invoquée pour informer le système
d'affichage de Swing que les composants
situés derrière peuvent être visibles et
doivent en conséquence être affichés
} // ZoneDessin
© Philippe GENOUD
Mai 2005
UJF
17
Dessiner
Dessiner en
en Java
Java
GUI
rafraichissement
rafraichissement du
du dessin
dessin
import java.awt.event.*;
import java.awt.*;
Import java.swing.*;
public class BarreOutils extends JPanel {
public BarreOutils(final ZoneDessin zd) {
...
JButton bDefaire = new JButton("Défaire");
this.add(bDefaire);
JButton bEffacer = new JButton("Tout effacer");
this.add(bEffacer);
...
bDefaire.addActionListener(
Annule le dernier tracé
new ActionListener() {
public void actionPerformed(ActionEvent e)
{
zd.annule();
}
}
Efface toute la zone de dessin
•type d ’événement ActionEvent
•source les JButton
•interface d ’écoute ActionListener
);
bEffacer.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e)
{
zd.efface();
}
}
récepteurs : utilisation de
classes anonymes dans le
constructeur de la Barre
d ’Outils
);
...
}
© Philippe GENOUD
UJF
Mai 2005
18
9
Dessiner
Dessiner en
en Java
Java
GUI
rafraichissement
rafraichissement du
du dessin
dessin
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class ZoneDessin extends Jpanel
implements MouseMotionListener {
Prise en compte des opérations annule
et effacer sur la zône de dessin
private BarreEtat be;
private int xInit, yInit;
Dessin dessin new Dessin();
1) Modification de l’objet
mémorisant le dessin
public ZoneDessin(BarreEtat be) {
...
}
2) réaffichage de la zône de
dessin
public void initieDroite(int x, int y) {
...
}
il faut prévenir l’application que
le dessin a changé et qu’il faut
rafraîchir le composant
méthode repaint() se charge
de rappeler la méthode
d’affichage du composant
(paintComponent) avec le bon
contexte graphique
public void termineDroite(int x, int y) {
...
}
...
public void paintComponent(Graphics g) {
...
}
public void annule() {
dessin.annule();
repaint();
}
public void efface() {
dessin.efface();
repaint();
}
} // ZoneDessin
© Philippe GENOUD
GUI
19
De
De AWT
AWT àà Java
Java 2D
2D
sérieuses limitations des possibilités graphiques de awt
Mai 2005
UJF
primitives graphiques limitées (lignes, rectangles, ovales...)
dessin des lignes avec épaisseur d'un seul pixel
peu de polices de caractères disponibles
pour appliquer une rotation ou une translation à quelque chose il faut le faire soi-même
support rudimentaire pour les images
contrôle de la transparence très difficile
...
introduction de nouvelles API pour le graphique avec version 2 de Java Java 2D
Object
de nouvelles classes dans les packages :
• java.awt
•java.awt.image
Graphics
java.awt.Graphics2D fourni des possibilités de dessin beaucoup plus élaborées
Graphics2D
This Graphics2D class extends the Graphics class to provide more sophisticated control over geometry,
coordinate transformations, color management, and text layout. This is the fundamental class for rendering
2-dimensional shapes, text and images on the Java(tm) platform
de nouveaux packages :
java.awt.color java.awt.font
java.awt.geom
© Philippe GENOUD
UJF
java.awt.print
java.awt.image.renderable
Mai 2005
20
10
GUI
Java2D
Java2D
Démonstration des possibilités de Graphics2D
programme de démonstration dans $JAVA_HOME/demo/jfc/JAVA2D/Java2Demo.jar
© Philippe GENOUD
UJF
Mai 2005
21
GUI
import
import
import
import
import
import
java.awt.Color;
java.awt.Dimension;
java.awt.Graphics;
java.awt.event.WindowAdapter;
java.awt.event.WindowEvent;
javax.swing.JFrame; import javax.swing.JPanel;
Pour illustrer les possibilités de l'API Java2D
on va débuter par un petit programme de dessin qui au
départ n'utilise pas Java 2D et qui sera ensuite modifié
(exemple tiré de :
The Java2D API, Bill Loeb, Dr Dobb's Journal, Février 1999)
public class DemoJava2D1 extends JPanel{
public DemoJava2D_1() {
setBackground(Color.WHITE);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.drawRect(100,100,100,100);
}
public static void main(String[] args) {
JFrame f = new JFrame("Demo Java 2D n°1");
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we){
System.exit(0);
}
});
f.add(new DemoJava2D_1());
f.setSize(new Dimension(400,400));
f.setVisible(true);
}
}
© Philippe GENOUD
UJF
Mai 2005
22
11
GUI
Utiliser
Utiliser l’objet
l’objet Graphics2D
Graphics2D
public void paintComponent(Graphics g)
En fait g est un objet Graphics2D,
(Graphics2D est une sous classe de Graphics)
On utilise le type Graphics pour des raisons de compatibilité
avec les versions antérieures de l’API java
Si on veut utiliser les fonctionnalités de Graphics2D il suffit de « downcaster » g
Graphics2D g2D = (Graphics2D) g;
g.draw(new Polygone(tabX, tabY, nbPts));
© Philippe GENOUD
GUI
Mai 2005
UJF
23
Utiliser
Utiliser l’objet
l’objet Graphics2D
Graphics2D
...
...
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.drawRect(100,100,100,100);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.BLUE);
g2d.setStroke(new BasicStroke(4.0f));
g2d.drawRect(100,100,100,100);
}
...
...
© Philippe GENOUD
UJF
Mai 2005
24
12
GUI
Utiliser
Utiliser des
des objets
objets Shape
Shape
...
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
1
Initialise le contexte
graphique
2
Défini et dessine un objet
(Rectangle)
g2d.setColor(Color.BLUE);
g2d.setStroke(new BasicStroke(4.0f));
g2d.drawRect(100,100,100,100);
}
...
Dans l'API Java 2D l'affichage peut être
séparé de la définition de l'objet.
en général 3 étapes pour dessiner des
objets
1.
2.
3.
Initialiser le contexte graphique
Définir l'objet à dessiner
Appeler l'une des méthodes de rendu
de Graphics2D pour afficher l'objet
Les objets implémentent l'interface
java.awt.Shape
Le package java.awt.geom propose
différentes classes d'implémentation de
Shape
© Philippe GENOUD
GUI
UJF
Mai 2005
25
Utiliser
Utiliser des
des objets
objets Shape
Shape
...
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
1
2
3
Initialise le contexte
graphique
Défini un objet
(Rectangle2D)
Appel de l'une des
méthodes de rendu
de Graphics2D
g2d.setColor(Color.BLUE);
g2d.setStroke(new BasicStroke(4.0f));
Rectangle2D r = new Rectangle2D.Float(100.0f,
100.0f, 200.0f, 200.0f);
g2d.draw(r);
}
...
<interface> Shape
Rectangle2D
Rectangle2D.Float
Rectangle2D.Double
2 classes selon le degré de
précision que l'on veut adopter
© Philippe GENOUD
UJF
Mai 2005
26
13
GUI
Shapes
Shapes :: package
package java.awt.geom
java.awt.geom
représente un point dans
l'espace utilisateur
Point2D
+ void setLocation(double x, double y)
+ void setLocation(Point2d p)
+ double getX()
+ double getY()
+ double distance(double x, double y)
+ double distance(Point2d p)
...
classes membre
statiques
Point2D.Double
Point2D.Float
Point
+ double x
+ double y
...
+ float x
+ float y
...
point ≠ pixel
1 point n'a pas de surface
utilisé pour définir la
géométrie des primitives
graphiques
+ int x
+ int y
...
public abstract class Point2D {
public static class Double extends Point2D {
public double x;
public double y;
...
}
java.awt
compatibilité avec versions
antérieures de java
public static class Float extends Point2D {
public float x;
public float y;
...
}
...
}
© Philippe GENOUD
GUI
Mai 2005
UJF
27
Shapes
Shapes :: package
package java.awt.geom
java.awt.geom
Line2D.Float
Line2D
Line2D.Double
Rectangle2D
RoundRectangle2D
RectangularShape
Ellipse2D
Arc2D
<interface>
Shape
QuadCurve2D
CubicCurve2D
forme arbitraire construite en spécifiant
une série de points pouvant être connectés
par des segments, courbes quadratiques ou cubiques
GeneralPath
Area
© Philippe GENOUD
opération booléennes sur deux formes
UJF
Mai 2005
28
14
GUI
Dessiner
Dessiner et
et remplir
remplir une
une forme
forme
Painting : remplir l'intérieur d'une forme (shape) avec une couleur, un
dégradé ou une texture , méthode fill de Graphics2D
Stroking : dessiner le contour (outline) d'une forme en spécifiant épaisseur
du trait (line width), le style de trait, méthode draw de Graphics2D
Graphics2D g2 = (Graphics2D)g;
double x = 15, y = 50, w = 70, h = 70;
Ellipse2D e = new Ellipse2D.Double(x, y, w, h);
remplir une forme
GradientPaint gp = new GradientPaint(75, 75,
Color.white,95, 95, Color.gray, true);
// Fill with a gradient.
g2.setPaint(gp); g2.fill(e);
// Stroke with a solid color.
e.setFrame(x + 100, y, w, h);
g2.setStroke(new BasicStroke(8));
g2.setPaint(Color.black);
g2.draw(e);
au contexte graphique comment
indique
remplir les formes. gp un objet qui
implémente interface java.awt.Paint
au contexte graphique de remplir
demande
la forme en la passant à la méthode fill
dessiner le contour d'une forme
au contexte graphique comment dessiner
indique
le contour des formes à l'aide d'un objet qui
implémente interface java.awt.Stroke
au contexte graphique comment remplir le
indique
contour à l'aide d'objet qui implémente interface
// Stroke with a gradient.
e.setFrame(x + 200, y, w, h);
g2.setPaint(gp);
g2.draw(e);
© Philippe GENOUD
java.awt.Paint
demande au contexte graphique de dessiner le
contour de la forme en la passant à la méthode
draw
UJF
GUI
29
Mai 2005
Stroke
Stroke
setStroke(Stroke s)
<interface> Stroke
BasicStroke
épaisseur du trait (line width) c'est un float
(1.0 environ 1 pixel 1/72 pouce lorsque transformation par défaut est appliquée)
style de jointure (joint style) manière dont segments se raccordent
JOIN_BEVEL
JOIN_METER
JOIN_ROUND
style de terminaison (end-cap) manière dont les extrémité des segments sont affichées
CAP_BUTT
CAP_ROUND
CAP_SQUARE
style de pointillé (dash style)
© Philippe GENOUD
UJF
Mai 2005
30
15
GUI
Stroke
Stroke
Tableau de flottant qui représente
la longueur des sections tracées et
non tracées du pointillé
- index pair (trait plein)
- index impair (espace)
...
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setPaint(Color.BLUE);
float dash[] = {20.0f, 10.0f};
g2d.setStroke(new BasicStroke(
4.0f,
// line width
BasicStroke.CAP_ROUND, // end cap style
BasicStroke.JOIN_BEVEL, // join style
0.0f,
// miter limit
dash,
// dash array
0.0f
// dash phase
));
Rectangle2D r = new Rectangle2D.Float(100.0f,
100.0f, 200.0f, 200.0f);
g2d.draw(r);
} ...
float dash[] =
{10.0f,6.0f,2.0f,6.0f};
© Philippe GENOUD
GUI
31
Mai 2005
UJF
Paint
Paint
setPaint(Paint p)
<interface> Paint
Color
couleur uniforme
GradientPaint
TexturePaint
remplissage avec une texture
dégradé de couleur
couleurs spécifiées par composantes primaires Rouge, Vert et Bleu
public Color(int r, int g, int b) 0 .. 255
public Color(float r, float g, float b)
0.0 .. 1.0
public Color(int rgb)
int
alpha
red
green
blue
0 255 0
Color.BLUE
0 0 255
Color.WHITE
255 255 255
Color.BLACK
000
Color.CYAN
0 255 255
Color.YELLOW
public Color(int a, int r, int g, int b) 0 .. 255
public Color(float a, float r, float g, float b)
0.0 .. 1.0
public Color(int argb, boolean hasAlpha)
UJF
255 0 0
Color.MAGENTA 255 0 255
Par défaut couleurs définies comme opaques
Couleur partiellement transparente définie à l'aide canal alpha
© Philippe GENOUD
Color.RED
Color.GREEN
Mai 2005
255 255 0
opaque
transparent
32
16
GUI
Paint
Paint
g2d.setStroke(new BasicStroke(4.0f));
Rectangle2D r = new Rectangle2D.Float(100.0f, 100.0f, 200.0f, 200.0f);
g2d.setPaint(…);
g2d.fill(r);
g2d.setPaint(Color.RED);
g2d.draw(r);
Color
TexturePaint
GradientPaint
© Philippe GENOUD
UJF
Mai 2005
GUI
33
Paint
Paint
g2d.setStroke(new BasicStroke(4.0f));
Rectangle2D r = new Rectangle2D.Float(100.0f, 100.0f, 200.0f, 200.0f);
g2d.setPaint(…);
g2d.fill(r);
g2d.setPaint(Color.RED);
g2d.draw(r);
g2d.setPaint(Color.BLUE);
© Philippe GENOUD
GradientPaint gp = new GradientPaint(
100.f, 100.f, // starting point
Color.BLUE,
// starting color
200.f, 200.f, // ending point
Color.GREEN // ending color );
g2d.setPaint(gp);
UJF
Mai 2005
34
17
GUI
Paint
Paint
g2d.setStroke(new BasicStroke(4.0f));
Rectangle2D r = new Rectangle2D.Float(100.0f, 100.0f, 200.0f, 200.0f);
g2d.setPaint(…);
g2d.fill(r);
g2d.setPaint(Color.RED);
g2d.draw(r);
Création ou
récupération
de l'image
définissant
la texture
Création
de l'objet
texture
BufferedImage bi = new BufferedImage(
6, // width
6, // height
BufferedImage.TYPE_INT_RGB // RGB image
);
Graphics2D big = bi.createGraphics();
big.setColor(Color.BLUE);
big.fillRect(0,0,6,6);
big.setColor(Color.GREEN);
big.fillRect(2,2,4,4);
Rectangle2D rTexture = new
Rectangle2D.Float(0.0f, 0.0f, 6.0f, 6.0f);
TexturePaint tp = new TexturePaint(bi,rTexture);
g2d.setPaint(tp);
© Philippe GENOUD
UJF
GUI
Mai 2005
35
Rendering
Rendering Hints
Hints
Ellipse2D r = new Ellipse2D.Float(100.0f,
100.0f, 200.0f, 200.0f);
GradientPaint gp =
new GradientPaint(
100.f, 100.f, // starting point
Color.BLUE, // starting color
200.f, 200.f, // ending point
Color.GREEN // ending color );
g2d.setPaint(gp); // g2d.fill(r);
g2d.setStroke(new BasicStroke(10.0f));
g2d.draw(r);
© Philippe GENOUD
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON
);
g2d.setRenderingHint(
RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY
);
UJF
Mai 2005
36
18
GUI
Transformations
Transformations géométriques
géométriques
Graphics2D maintient une transformation géométrique appliquée au primitives
géométriques avant qu'elles ne soient rendues.
attribut défini comme une instance de AffineTransform
transformation affine : lignes parallèles demeurent parallèles
composition de transformations élémentaires
translation
rotation
x' = x + tx
y' = y + ty
x' = x . cos(Θ) - y . sin(Θ)
y' = x . sin(Θ) + y . cos(Θ)
homothétie (scaling)
shearing
x' = a . x
y' = b . y
x' = x + shx . y
y' = y
ou
x' = x
y' = shy . x + y
même l'épaisseur du
trait est affecté !
Une épaisseur de 0.0
produira un tracé le
plus fin possible
© Philippe GENOUD
maintient représentation source d'une matrice 3x3 d'une transformation affine
[x'] = [m00
[y'] = [m10
[1] = [ 0
m01
m11
0
m02] [x] = [m00x + m01y + m02]
m12] [y] = [m10x + m11y + m12]
1 ] [1] = [
1
]
factory méthodes pour construire de transformations élémentaires
public
public
public
public
public
37
Mai 2005
transformations
transformations géométriques
géométriques
AffineTransform
AffineTransform
GUI
UJF
static
static
static
static
static
AffineTransform
AffineTransform
AffineTransform
AffineTransform
AffineTransform
getTranslateInstance(double tx,double ty)
getRotateInstance(double theta)
getRotateInstance(double theta,double x,double y)
getScaleInstance(double sx,double sy)
getShearInstance(double shx,double shy)
composition de transformations
public void concatenate(AffineTransform Tx)
[this] = [this] x [Tx]
Tx sera appliquée en premier aux coordonnées des primitives géométriques
Composition n'est pas commutative. L'ordre des transformations compte !
translation puis rotation
rotation puis translation
public void preConcatenate(AffineTransform Tx)[this] = [Tx] x [this]
© Philippe GENOUD
UJF
Mai 2005
38
19
GUI
transformations
transformations géométriques
géométriques
Graphics 2D gère une transformation affine courante
Graphics2D passé en paramètre de paintComponent initialisée avec une
transformation par défaut plaçant origine dans le coin supérieur gauche de la
surface de dessin du composant
Modification de la transformations courante
public abstract void setTransform(AffineTransform Tx)
remplace la transformation courante
public abstract void transform(AffineTransform Tx)
concaténation à la transformation
courante
public
public
public
public
abstract
abstract
abstract
abstract
void translate(double tx, double ty)
void rotate(double theta)
void rotate(double theta, double x, double y)
shear(double shx, double shy)
attention setTransform écrase la transformation courante qui peut être utilisée pour d'autres choses
(par exemple pour positionner les composants swing contenus dans la fenêtre)
utiliser les étapes suivantes
pour appliquer des
transformations
utiliser getTransform pour récupérer la transformation courante
utiliser transform, translate, scale, shear ou rotate pour
modifier la transformation courante
effectuer le rendu
restituer la transformation originale en utilisant setTransform
© Philippe GENOUD
GUI
UJF
Mai 2005
39
transformations
transformations géométriques
géométriques
g2d.setStroke(new BasicStroke(4.0f));
Rectangle2D r = new Rectangle2D.Float(100.0f, 100.0f, 200.0f, 200.0f);
AffineTransform t =
new AffineTransform();
t.rotate(Math.toRadians(45));
g2d.setTransform(t);
g2d.setPaint(Color.BLUE);
g2d.fill(r);
g2d.setPaint(Color.RED);
g2d.draw(r);
AffineTransform t =
new AffineTransform();
t.translate(200,200);
t.rotate(Math.toRadians(45));
t.translate(-200,-200);
g2d.setTransform(t);
© Philippe GENOUD
UJF
Mai 2005
40
20
GUI
transformations
transformations géométriques
géométriques
possibilité de modifier les coordonnées d'une primitive graphique
sans modifier transformation courante de Graphics2D
création d'une nouvelle Shape
public Shape createTransformedShape(Shape pSrc)
public Point2D transform(Point2D ptSrc, Point2D ptDst)
public void transform(Point2D[] ptSrc,int srcOff,Point2D[] ptDst,
int dstOff,numPts)
public Point2D deltaTransform(Point2D ptSrc, Point2D ptDst)
public void deltaTransform(double[] srcPts, int srcOff, double[] dstPts,
int dstOff, int numPts)
pour transformer un vecteur ("delta") représenté par un point.
N'applique pas la composante de translation de la transformation courante
© Philippe GENOUD
GUI
UJF
Mai 2005
41
Créer
Créer se
se propres
propres formes
formes
GeneralPath gp = new GeneralPath();
Line2D l1 = new Line2D.Float(50.f,100.f,100.f,100.f);
gp.append(l1,true);
CubicCurve2D cc = new CubicCurve2D.Float(
100.0f, 100.0f, // starting point
125.0f, 125.0f, // control point 1
150.0f, 125.0f, // control point 2
175.0f, 100.0f // ending point );
gp.append(cc,true);
Line2D l2 = new Line2D.Float(175.0f,100.0f,
225.0f,100.0f);
gp.append(l2,true);
g2d.setStroke(new BasicStroke(4.0f));
g2d.setPaint(Color.BLUE);
g2d.draw(gp);
for (int i = 0; i < 10; i++) {
g2d.translate(20,20);
g2d.draw(gp);
}
© Philippe GENOUD
UJF
Mai 2005
42
21
GUI
Créer
Créer se
se propres
propres formes
formes
Rectangle2D r =
new Rectangle2D.Float(100.0f, 100.0f, 100.0f, 100.0f);
Ellipse2D e = new Ellipse2D.Float(150.0f, 150.0f, 25.0f,
25.0f);
Area a = new Area(r);
a.subtract(new Area(e));
g2d.setStroke(new BasicStroke(4.0f));
g2d.setPaint(Color.BLUE);
g2d.fill(a);
g2d.setPaint(Color.RED);
g2d.draw(a);
g2d.translate(120,120);
g2d.translate(150,150);
g2d.scale(2,2);
g2d.rotate(Math.toRadians(45));
g2d.translate(-150,-150);
g2d.draw(a);
© Philippe GENOUD
GUI
UJF
Mai 2005
Support
Support de
de l'interaction
l'interaction utilisateur
utilisateur
Pour interagir avec les dessins affichés nécessité de déterminer lorsque
l'utilisateur clique sur l'un deux.
deux manières de procéder
43
en utilisant la méthode hit de Graphics2D
public abstract boolean hit(Rectangle rect, Shape s,
boolean onStroke)
true si la forme s intersecte le rectangle rect exprimé en
coordonnées écran (device coordinates)
en utilisant la méthode contains de l'objet Shape
public boolean contains(double x, double y)
true si la forme s contient le point x, y exprimé en coordonnées
écran (device coordinates)
© Philippe GENOUD
UJF
Mai 2005
44
22
GUI
Attributs
Attributs du
du contexte
contexte Graphics2D
Graphics2D
style de pinceau (pen style) pour dessiner le contour des formes
épaisseur du trait, pointillé, ...
setStroke
style de remplissage (fill style) appliqué à l'intérieur des formes
couleur de remplissage, dégradés, textures.
setPaint
style de composition (composition style) utilisé quand les objets
affichés recouvrent d'autres objets (transparence,...)
setComposite
transformation géométrique. Application de transformation
géométriques (translations, rotations, homothétie (scaling),
shearing...) aux formes
setTransform
clipping. Restreint l'affichage à une région définie par
une forme géométrique
setClipping
police (font) utilisée pour le texte
setFont
rendering hints : préférence dans compromis entre rapidité et
qualité du rendu. par exemple pour spécifier si antialiasing
doit être utilisé où non
setRenderingHints
© Philippe GENOUD
UJF
GUI
45
Mai 2005
Rendu
Rendu dans
dans java
java 2D
2D
Graphics2D
Graphics
primitives
fill()
Shapes
draw()
Text
drawString()
Images
drawImage()
transformation
transformation
stroke
stroke
font
font
rendering
rendering hints
hints
rasterizer
rasterizer
clipping
clipping shape
shape
paint
paint
composition
composition rule
rule
Dispositifs
d'affichage
écran
imprimante
images
d'après JAVA 2D Graphics de Jonathan Knudsen, Ed. Oreilly
© Philippe GENOUD
UJF
Mai 2005
46
23