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