5. GRAPHISME AVEC L'AWT
 

Il existe actuellement deux bibliothèques standards en Java pour le graphisme, l'AWT (Abstract Window Toolkit) et Swing. La seconde est plus récente, mais plus délicate à manipuler. Nous proposons donc de présenter plutôt des composants de l'AWT qui se trouvent dans le package java.awt.

 
COMPOSANTS GRAPHIQUES
 

La première chose à faire dans toute interface graphique est de fournir une ou plusieurs fenêtres qui vont accueillir les composants graphiques de l'application. Nous nous intéressons simplement ici à l'ouverture d'une fenêtre dans laquelle on peut dessiner simplement. Mais il faut savoir que l'AWT propose une hiérarchie de nombreux composants graphiques comme des boutons, des menus déroulants..., tous héritant de la super-classe Component. L'exemple qui suit ouvre deux fenêtres, chacune contenant un composant simple, de la classe Panel, qui prend tout l'espace de la fenêtre, et dans lequel est affiché un rectangle.

import java.awt.*;

public class Fenetre extends Frame {
 protected Panneau panneau;

 public Fenetre(String titre) {
  super(titre);
// Appelle le constructeur de la super-classe.
  panneau=new Panneau(); // Crée un panneau.
  setLayout(new BorderLayout()); // Crée le gestionnaire de placement.
  add(panneau,BorderLayout.CENTER); // Place le panneau dans la fenêtre.
  pack(); // Dimensionne la fenêtre et ses composants.
  setResizable(false); // Indique que la fenêtre n'est pas redimensionnable.
  setVisible(true); // Affiche la fenêtre.
 }

 public Dimension getPreferredSize()
// Utilisée par la méthode pack pour
 { return (new Dimension(200,200)); } // connaître la taille de la fenêtre.

 public static void main(String args[]) {
  new Fenetre("Fenetre 1");
  new Fenetre("Fenetre 2");
 }
}

class Panneau extends Panel {
 public Panneau() { super(); }

 public void paint(Graphics g) {
  super.paint(g);
  g.drawRect(10,10,getWidth()-20,getHeight()-20);
 }
}

La classe Fenetre hérite de Frame, dont le constructeur reçoit une chaîne de caractères qui est le titre de la fenêtre. Dans le constructeur de Fenetre, un composant Panel est créé et positionné sur la fenêtre. La méthode setLayout permet de spécifier quel est le gestionnaire chargé de positionner les composants sur la fenêtre. Nous utilisons ici un gestionnaire de la classe BorderLayout, qui permet de positionner les composants de manière relative, mais il en existe d'autres avec des politiques de placement différentes. La méthode add ajoute le composant Panel dans la fenêtre, en demandant de le centrer (grâce à BorderLayout.CENTER). Le gestionnaire le positionnera ensuite automatiquement, mais étant le seul composant, il occupera tout l'espace de la fenêtre. La méthode pack redimensionne la fenêtre et les composants qu'elle contient, et pour connaître la taille de la fenêtre, elle interroge sa méthode getPreferredSize. Les méthodes setResizeable et setVisible indiquent respectivement que la fenêtre n'est pas redimensionnable et qu'elle est visible.

La méthode paint dessine un rectangle dans le composant Panel, mais cette opération sera détaillée plus tard. Notons simplement que la méthode paint est appelée chaque fois que l'on a besoin d'afficher le composant (i.e. la première fois qu'il apparaît à l'écran, lorsqu'une fenêtre qui cachait le composant le dévoile à nouveau...). Il est d'usage de mettre dans cette méthode le code correspondant à l'affichage du composant.

 
GESTION DES EVENEMENTS
 

En exécutant l'exemple précédent, on s'aperçoit qu'il est impossible de fermer les fenêtres, simplement parce que l'événement engendré par le clic de la souris sur le bouton de fermeture de la fenêtre n'a pas été récupéré et traité par le programme. Pour cela, il faut mettre en place des objets, les listeners, chargés de cette écoute. Ils appartiennent à la classe (ou plus exactement à l'interface) EventListener. Par exemple, lorsque l'événement de fermeture de la fenêtre est levé, la méthode windowClosing du listener attaché à la fenêtre est exécutée.

 
Evénements d'une fenêtre
 

Pour traiter cet événement, il faut donc créer un listener de fenêtre, de la classe WindowAdapter, et redéfinir sa méthode windowClosing. Il suffit ensuite de le rattacher à la fenêtre par la méthode addWindowListener. L'exemple précédent est complété pour que la fermeture des fenêtres soit possible. L'une des deux fenêtres, la fenêtre maîtresse terminera l'application lorsqu'elle se fermera, alors que l'autre, la fenêtre esclave, ne stoppera pas l'application à sa fermeture.

import java.awt.*;
import java.awt.event.*;

public class Fenetre extends Frame {
 protected boolean maitre;
 protected Panneau panneau;

 protected class EvenementFenetre extends WindowAdapter {
  public void windowClosing(WindowEvent e) {
   dispose();
// Ferme la fenêtre.
   if (maitre) System.exit(0);
  }
 }


 public Fenetre(String titre,boolean m) {
  super(titre);
  panneau=new Panneau();
  maitre=m;
  setLayout(new BorderLayout());
  add(panneau,BorderLayout.CENTER);
  addWindowListener(new EvenementFenetre());
  pack();
  setResizable(false);
  setVisible(true);
 }

 public Dimension getPreferredSize()
 { return (new Dimension(200,200)); }

 public static void main(String args[]) {
  new Fenetre("Fenetre maitresse",true);
  new Fenetre("Fenetre esclave",false);
 }
}

Toutes les classes permettant la gestion des événements des composants graphiques se trouvent dans le package java.awt.event.

 
Evénements du clavier
 

Pour gérer les événements du clavier, le mécanisme est identique à celui des événements d'une fenêtre. La différence ici est la classe du listener, qui est KeyAdapter, et donc les méthodes à redéfinir. Le plus simple pour introduire tous les événements importants est un exemple. Voici un listener pour les événements du clavier.

protected class EvenementClavier extends KeyAdapter {
 public void keyPressed(KeyEvent e) {
  if (e.getKeyChar()==KeyEvent.CHAR_UNDEFINED)
   System.out.println(getTitle()+", touche de controle "
                      +e.getKeyCode()+" enfoncee...");
  else
   System.out.println(getTitle()+", touche '"
                      +e.getKeyChar()+"' enfoncee...");
 }

 public void keyReleased(KeyEvent e) {
  if (e.getKeyChar()==KeyEvent.CHAR_UNDEFINED)
   System.out.println(getTitle()+", touche de controle "
                      +e.getKeyCode()+" relachee...");
  else
   System.out.println(getTitle()+", touche '"
                      +e.getKeyChar()+"' relachee...");
 }
}

Le listener capture entre autres deux types d'événements: "une touche est enfoncée" (la méthode keyPressed est appelée) et "une touche est relâchée" (la méthode keyReleased est appelée). Les méthodes appelées lors d'un événement du clavier reçoivent un paramètre de la classe KeyEvent. Deux méthodes getKeyChar et getKeyCode de cet objet permettent respectivement de récupérer soit le caractère associé à la touche impliquée dans l'événement, soit directement son code. La méthode getKeyChar retourne KeyEvent.CHAR_UNDEFINED si la touche n'a pas de caractère associé. La méthode getKeyCode retourne un entier, mais des constantes symboliques sont fournies pour déterminer plus facilement quelle touche a été appuyée ou relâchée. Voici un extrait de ces codes.

Constante Touche
VK_LEFT Flèche gauche
VK_RIGHT Flèche droite
VK_UP Flèche haut
VK_DOWN Flèche bas
VK_PAGE_UP Flèche page haut
VK_PAGE_DOWN Flèche page bas
VK_TAB Tabulation
VK_BACK_SPACE Backspace
VK_SHIFT Shift
VK_CONTROL Ctrl
VK_ALT Alt
VK_ALT_GRAPH Alt Gr

Il ne faut pas oublier de rattacher le listener de clavier à la fenêtre, pour cela il faut rajouter la ligne suivante dans le constructeur de la fenêtre, de manière semblable au listener de fenêtre.

addKeyListener(new EvenementClavier());

 
Evénements de la souris
 

Pour gérer les événements de la souris, le mécanisme est identique aux autres types d'événements. La classe du listener à dériver dans ce cas est MouseAdapter. Voici un exemple de listener pour les événements de la souris. Ce listener est placé sur le composant Panel. C'est sur lui que l'on clique, il reçoit donc les événements de la souris.

class Panneau extends Panel {
 protected class EvenementSouris extends MouseAdapter {
  public void mousePressed(MouseEvent e)
  { getGraphics().drawRect(e.getX(),e.getY(),1,1); }

  public void mouseReleased(MouseEvent e)
  { System.out.println("Souris relachee..."); }
 }


 public Panneau() {
  super();
  addMouseListener(new EvenementSouris());
 }

 public boolean isFocusTraversable() { return false; }

 public void paint(Graphics g) {
  super.paint(g);
  g.drawRect(10,10,getWidth()-20,getHeight()-20);
 }
}

Lorsque l'on clique sur le composant Panel, le focus du clavier lui est attribué par défaut. Ce qui signifie que le listener de clavier attaché à la fenêtre ne reçoit plus les événements du clavier. Pour éviter cette perte de focus, il suffit d'indiquer que le composant Panel ne désire pas obtenir le focus, en redéfinissant la méthode isFocusTraversable pour qu'elle retourne false.

 
DESSINER
 

Il est possible de dessiner dans la plupart des composants héritant de la classe Component, mais cela ne se fait pas directement, il faut utiliser un intermédiaire, un contexte graphique, un objet de la classe Graphics. Pour l'obtenir, il suffit d'appeler la méthode getGraphics du composant, elle retourne alors un objet de cette classe (cf. la méthode mousePressed de l'exemple précédent). Mais certaines méthodes, comme paint, reçoivent directement cet objet en paramètre (cf. l'exemple précédent). Un contexte graphique possède des méthodes pour afficher des formes dans le composant qu'il référence. Le tableau suivant récapitule les plus importantes.

Méthode Description
drawArc(x,y,l,h,a1,a2) Trace un arc de cercle dans le rectangle de coin (x;y), de largeur l et de hauteur h. L'arc commence à l'angle a1 et se termine à l'angle a2, exprimés en degré.
fillArc(x,y,l,h,a1,a2) La même chose avec une forme pleine.
drawLine(x1,y1,x2,y2) Trace une ligne entre les coordonnées (x1;y1) et (x2;y2).
drawRect(x,y,l,h) Trace un rectangle de coin (x;y), de largeur l et de hauteur h.
fillRect(x,y,l,h) La même chose avec une forme pleine.
drawString(s,x,y) Dessine la chaîne de caractères s aux coordonnées (x;y).

Il est possible de spécifier la couleur des formes dessinées, pour cela il faut utiliser la méthode setColor du contexte graphique. Elle attend en paramètre une couleur qui est un objet de la classe Color. Des couleurs sont prédéfinies dans la classe, par exemple Color.red, Color.green... Mais il est possible de définir ses propres couleurs en indiquant leur code RGB (Red / Green / Blue), c'est-à-dire leur niveau de rouge, de vert et de bleu, ces valeurs étant des flottants entre 0 et 1. L'exemple suivant dessine un rectangle orange dans le contexte graphique du composant courant.

Graphics g = getGraphics();
g.setColor(new Color((float)1.0,(float)0.5,(float)0.0));
g.fillRect(50,50,100,100);

 
 
Copyright (c) 1999-2016 - Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net
La permission est accordée de copier, distribuer et/ou modifier ce document sous les termes de la licence GNU Free Documentation License, Version 1.1 ou toute version ultérieure publiée par la fondation Free Software Foundation. Voir cette licence pour plus de détails (http://www.gnu.org).