Bibliothèque graphique |
|
Pour faciliter l'accès aux fonctionnalités graphiques de Java, nous avons défini pour ce cours le package graphique. Les types de ce paquet et leurs membres publics ont tous un nom en français afin de les distinguer des types de la bibliothèque standard de Java (API Java 2).
Le tableau ci-dessous précise le nom des paquets dans lesquels sont définis les types cités dans ce document.
Sauvegardez le fichier d'archives graphique.tgz dans votre répertoire ~/info/classes, placez-vous dans ce répertoire et extrayez les fichiers de classe qu'il contient au moyen de :
tar zxvf graphique.tgz
Ceci crée un répertoire graphique sous ~/info/classes, qui contient les fichiers de classe nécessaires.
Pour pouvoir réaliser des dessins dans une fenêtre, on doit étendre la classe FenetreGraphique du paquet graphique. Cette classe permet d'ouvrir une fenêtre graphique composée de haut en bas d'une barre de menu (avec un menu Fichier), d'une zone de dessin et d'une ligne d'information :
La méthode void dessiner(Graphics2D g2), qui par défaut ne fait rien, est appelée quand une demande d'affichage de la zone de dessin a lieu. Elle doit être redéfinie dans une extension de la classe FenetreGraphique. La re-définition de cette méthode doit contenir les instructions nécessaires à la réalisation du tracé qui apparaîtra dans la zone de dessin. Cette méthode possède un paramètre g2 appelé contexte graphique qui rassemble les attributs courants relatifs au tracé comme par exemple l'épaisseur du trait, la couleur de remplissage, etc.
La méthode void re_dessiner() provoque le ré-affichage du contenu de la fenêtre de dessin : la zone de dessin est effacée puis la méthode précédente est appelée. Cette méthode doit être appelée lorsque le dessin a changé.
import java.awt.*; import graphique.FenetreGraphique; class Ex1 extends FenetreGraphique { Ex1 () {} Ex1 (int w, int h, Color c) {super(w,h,c);} public void dessiner(Graphics2D g2) { g2.setPaint(Color.red); g2.drawString("ENPC", 0, getHauteur()); } } class Ex1Main { public static void main(String[] args) { FenetreGraphique fenêtre = new Ex1(); fenêtre.ouvrir(); fenêtre.informer("Un premier exemple"); } }
Les segments de droite sont représentés par des objets de la classe Line2D. On en obtient une instance en appelant le constructeur suivant :
Line2D.Float(float x1, float y1, float x2, float y2)qui crée un segment de droite reliant le point (x1,y1) au point (x2,y2)
Les rectangles sont représentés par des objets de la classe Rectangle2D. On en obtient une instance en appelant le constructeur suivant :
Rectangle2D.Float(float x, float y, float w, float h)qui crée un rectangle de largeur w et de hauteur h dont le coin supérieur gauche est situé au point de coordonnées (x,y)
Les ellipses sont représentées par des objets de la classe Ellipse2D. On en obtient une instance en appelant le constructeur suivant :
Ellipse2D.Float(float x, float y, float w, float h)qui crée une ellipse de grand axe w et de petit axe h dont le coin supérieur gauche du rectangle englobant est situé au point de coordonnées (x,y)
void dessinePoint(Graphics2D g2, Point p) { float d = 5; // diamètre du cercle // Crée un petit cercle de 5 unités de diamètre, centré en p Shape c = new Ellipse2D.Float(p.x-d/2, p.y-d/2, d, d); // Fixe la couleur de tracé g2.setPaint(Color.yellow); // Dessine le cercle g2.draw(c); }
Les arcs d'ellipses sont représentés par des objets de la classe Arc2D. On en obtient une instance en appelant le constructeur suivant :
Arc2D.Float(float x, float y, float w, float h, float start, float extent, int type)qui crée un arc d'ellipse. L'ellipse est spécifiée par les paramètres x,y,w,h comme ci-dessus. L'arc démarre à l'angle start et s'étend d'un angle extent ; les angles sont comptés positivement à partir de l'axe des x dans le sens trigonométrique et doivent être donnés en degrés. L'argument type sert à spécifier comment l'arc est fermé, il peut prendre l'une des valeurs Arc2D.OPEN, Arc2D.CHORD, ou Arc2D.PIE pour obtenir respectivement un arc ouvert, fermé selon la corde ou selon des rayons partant des extrémités de l'arc (part de gâteau).
Les polygones quelconques sont représentées par des objets de la classe GeneralPath. On en obtient une instance en appelant le constructeur suivant :
GeneralPath()crée un chemin vide. Pour ajouter des segments à un chemin, on doit invoquer sur lui l'une des méthodes suivantes :
void moveTo(float x, float y)ajoute le point de coordonnées x,y au chemin. Aucun segment ne relie le point courant à ce point.
void lineTo(float x, float y)ajoute le point de coordonnées x,y au chemin. Le point courant est relié à ce point par un segment de droite.
void closePath()ferme le chemin en reliant par un segment de droite le point courant au point inséré par le dernier appel à moveTo().
FontMetrics fm = g2.getFontMetrics(f);où g2 est le contexte graphique courant. Sur l'objet fm obtenu, on peut par exemple obtenir la largeur d'une chaîne de caractères s dessinée avec la police f en évaluant l'expression :
fm.stringWidth(s)
int getWidth(ImageObserver obs)retourne la largeur en pixels de cette image. Le paramètre obs doit recevoir la valeur null.
int getHeight(ImageObserver obs)retourne la hauteur en pixels de cette image. Le paramètre obs doit recevoir la valeur null.
g2.setPaint(Color.blue);où g2 est le contexte graphique courant.
Color(float r, float v, float b)crée une couleur composée d'une proportion r de rouge, v de vert et b de bleu. Les proportions doivent être dans l'intervalle $[0,1]$. L'attribut de couleur est fixée par la méthode
void setPaint(Paint paint)
BasicStroke(float w)crée un crayon dont la largeur de tracé est w. La largeur du trait est fixée par la méthode
void setStroke(Stroke s)
Font(String nom, int style, int taille)crée une nouvelle police. Le paramètre nom est le nom logique d'une police, les noms disponibles sont "Dialog", "DialogInput", "Monospaced", "Serif", "SansSerif" ou Symbol. Le paramètre style peut prendre la valeur Font.PLAIN pour le style standard, Font.BOLD pour avoir des caractères gras ou Font.ITALIC pour avoir des caractères penchés ou bien la combinaison Font.BOLD | Font.ITALIC pour une combinaison ces deux styles. Le paramètre taille indique la taille en points de cette police, le << point >> valant approximativement $1/72$ de pouce. La police de caractères est fixée par la méthode
setFont(Font font)
void draw(Shape s)trace le contour de la forme géométrique s en utilisant les attributs de couleur et de tracé du contexte graphique courant.
void fill(Shape s)remplit l'intérieur de la forme géométrique s dans la couleur courante.
void drawString(String s, float x, float y)dessine le texte spécifié par la chaîne s dans la couleur et la police de caractères courantes. L'origine de la ligne de base du premier caractère est à la position x,y.
boolean drawImage(Image img, int x, int y, ImageObserver obs)dessine l'image img. Le coin supérieur gauche de l'image est placée à la position x,y. Le dernier paramètre doit recevoir la valeur null. On obtient un objet de type Image par un appel à la méthode chargerImage().
Un événement clavier est un objet de type KeyEvent qui est produit lorsque l'utilisateur tape sur une touche de son clavier. Ce type est défini dans le paquet java.awt.event.
Il y a trois sortes d'événements clavier correspondant respectivement à l'enfoncement d'une touche, le relâchement d'une touche et la séquence enfoncement / relâchement d'une touche associée à un caractère. Le traitement d'un événement est confié à une méthode ayant un prototype standardisé, spécialisée pour un type donné d'événement.
Ci-dessous, quelques méthodes utiles définies sur ce type.
char getKeyChar()retourne le caractère associé à la touche. Pour une touche non associée à un caractère, retourne la valeur de la constante CHAR_UNDEFINED.
int getKeyCode()retourne le code clavier associé à la touche. Une constante de type int est définie pour chacune des touches du clavier. Par exemple, la touche A a pour code clavier la valeur de la constante VK_A.
boolean isShiftDown() boolean isControlDown() boolean isMetaDown()retourne l'état (enfoncé ou non) des touches Shift, Control et Meta respectivement.
Un événement souris est un objet de type MouseEvent qui est produit lorsque l'utilisateur déplace sa souris ou clique sur un bouton. Ce type est défini dans le paquet java.awt.event. Il y a plusieurs sortes d'événements souris :
int getClickCount()retourne le nombre de clics : 1 pour un simple clic, 2 pour un double, etc.
int getX() int getY() Point getPoint()retourne les coordonnées (x,y) du pointeur dans le repère de la zone de dessin.
boolean isShiftDown() boolean isControlDown() boolean isMetaDown()retourne l'état (enfoncé ou non) des touches Shift, Control et Meta respectivement.
int getModifiers()retourne un entier indiquant l'état des boutons de la souris. Par exemple, l'expression suivante est vraie si le bouton 2 de la souris a été enfoncé :
(e.getModifiers() & InputEvent.BUTTON2_MASK) == InputEvent.BUTTON2_MASKoù e est un objet de type MouseEvent.
List points = new ArrayList(); public void mouseClicked(MouseEvent e) { // Si clic gauche, ajoute un point à la liste if ((e.getModifiers() & InputEvent.BUTTON1_MASK) == InputEvent.BUTTON1_MASK) points.add(e.getPoint()); else // Sinon retire tous les points de la liste points.clear(); // Demande le ré-affichage de la liste de points re_dessiner(); }
Il est possible d'ajouter d'autres items de menu au menu existant et d'autres menus à la barre de menus de la façon suivante :
import java.awt.*; import javax.swing.*; import graphique.FenetreGraphique; class Ex4 extends FenetreGraphique { JMenuBar jmb; JMenu jm0, jm1; JMenuItem jmi0, jmi1; Ex4 () { étendreMenus(); } Ex4 (int w, int h, Color c) { super(w,h,c); étendreMenus(); } void étendreMenus() { // la barre de menu jmb = getJMenuBar(); // le premier menu jm0 = jmb.getMenu(0); // addition d'un item de menu jmi0 = new JMenuItem("Item de menu"); jm0.add(jmi0); // addition d'un menu jm1 = new JMenu("Nouveau menu"); jmi1 = new JMenuItem("Item de menu"); jm1.add(jmi1); jmb.add(jm1); } // ... }
Une fenêtre de dialogue permet de saisir des données.
import java.awt.*; import java.awt.event.*; import javax.swing.*; import graphique.FenetreGraphique; class Ex6 extends FenetreGraphique { Ex6 () { } Ex6 (int w, int h, Color c) { super(w,h,c); } public void mouseClicked(MouseEvent e) { // Si clic droit, ouvre une fenêtre de saisie if ((e.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK) { Saisie dialogue = new Saisie(this); dialogue.pack(); dialogue.setLocationRelativeTo(this); dialogue.setLocation(e.getPoint()); dialogue.show(); } } public void dessiner(Graphics2D g2) { g2.setPaint(Color.red); g2.drawString("ENPC", 0, getHauteur()); } } class Ex6Main { public static void main(String[] args) { FenetreGraphique fenêtre = new Ex6(); fenêtre.ouvrir(); fenêtre.informer("Exemple avec fenêtre de saisie"); } } class Saisie extends JDialog { FenetreGraphique parent; Container conteneur; GridLayout placement = new GridLayout(3,2); JLabel champ1Label = new JLabel("Le champ 1"); JTextField champ1Text = new JTextField(); JLabel champ2Label = new JLabel("Le champ 2"); JTextField champ2Text = new JTextField(); Action valider = new AbstractAction("Valider") { public void actionPerformed(ActionEvent e) { parent.informer(champ1Text.getText() + ", " + champ2Text.getText()); dispose(); } }; JButton validerButton = new JButton(valider); Action effacer = new AbstractAction("Effacer") { public void actionPerformed(ActionEvent e) { champ1Text.setText(""); champ2Text.setText(""); } }; JButton effacerButton = new JButton(effacer); // vérifie que les champs saisis sont numériques KeyListener kl = new KeyAdapter() { public void keyTyped(KeyEvent e) { char c = e.getKeyChar(); if (!((c >= '0') && (c <= '9') || (c == KeyEvent.VK_BACK_SPACE) || (c == KeyEvent.VK_DELETE))) { getToolkit().beep(); e.consume(); } } }; public Saisie(FenetreGraphique parent) { super((Frame)null, "Saisie des paramètres", true); this.parent = parent; this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); conteneur = getContentPane(); conteneur.setLayout(placement); this.setSize(new Dimension(400, 300)); this.setTitle("Saisie"); placement.setHgap(20); placement.setVgap(10); champ1Text.addKeyListener(kl); champ2Text.addKeyListener(kl); conteneur.add(champ1Label); conteneur.add(champ1Text); conteneur.add(champ2Label); conteneur.add(champ2Text); conteneur.add(validerButton); conteneur.add(effacerButton); } }
Last modified: Mon Nov 26 12:13:34 MET 2001