Introduction à JAVA

 Gestion du clavier et de la souris

Lorsque l'utilisateur d'une applet appuie sur une touche du clavier, déplace la souris, clique sur un bouton, le système d'exploitation de sa machine déclenche un événement .  Pour capturer les événement les concepteurs de JAVA ont introduit la classe Component. C'est la super-classe abstraite de la plupart des classes de l' " Abstract Window Toolkit " qui seront étudiées par la suite. (Les classes de Component représentent des entités ayant une position, une taille, pouvant être dessiné à l'écran ou pouvant recevoir des événements).
La classe Applet hérite de la classe Component et peut traiter les événements au moyen des méthodes de la classe Event de java.awt

A partir de la version 1.1 JAVA n'utilise plus la classe Event pour la gestion du clavier et de la souris !

 9.1 Gestion du clavier (Java 1.0.x)

 Pour récupérer les événements du clavier, il faut surcharger la méthode public boolean keyDown(Event evt, int key) . L'entier associé à la touche enfoncé est retourné dans la variable d'instance key. La classe Event définit des constantes pour les touches non alphanumériques du clavier. Pour tester les touches de modification du clavier, il existe également les méthodes shiftDown( ) (touche [majuscule]), controlDown( ) (touche [Ctrl]) et metaDown( ) (touche [Méta] ou [Alt]). La touche META est utilisée sur les systèmes UNIX. Son équivalent sur les systèmes Apple est la touche [Pomme].
Attention : Si l'applet n'a pas le focus elle ne peut pas récupérer les événements du clavier. Pour donner le focus à une applet il faut par exemple cliquer avec la souris dans son cadre ou utiliser la méthode requestFocus( ) comme dans l'exemple ci-dessous. Si vous cliquez en dehors du cadre de l'applet, celle-ci perd le focus.
Constantes associées aux touches non alphanumériques : Event.UP = 1004, Event.DOWN = 1005, Event.LEFT = 1006, Event.RIGTH  = 1007 (flèches); Event.HOME, Event.END, Event.PGUP, Event.PGDN, Event.F1 à Event.F12.
Constantes associées aux touches modificatrices : ALT_MASK = 8, CTRL_MASK = 2, META_MASK = 4, SHIFT_MASK = 0;

import java.applet.*;
import java.awt.*;

public class clavier extends Applet
{  char touche='@';
    int taille=20,code=touche,gras=0,c=125;
    boolean maj;

  public void init()
   {  setBackground(Color.lightGray);
      this.requestFocus();}  //donne le focus 

  public void paint(Graphics g)
   {  Color col = new Color(c,0,0);
      Font font = new Font("Helvetica",gras,taille);
      g.setFont (font);       g.setColor(col);
      g.drawString("taille = "+taille, 10, 60);
      g.drawString("Maj = "+maj, 10, 110);
      g.drawString(String.valueOf(touche)+" => "+code,10,170);}

  public boolean keyDown(Event evt, int key) //surcharge de la méthode
   {  switch(key){
        case Event.DOWN :      //constante pour la flèche bas
                if (taille>6)  taille--;  break;
        case 1004 :   //constante pour la flèche haut
                if (taille<55) taille++;  break;
        case Event.LEFT : if (c>0) c-=5;  break;
        case Event.RIGHT : if (c<255) c+=5; break;
        case Event.PGUP : gras=1; break;
        case Event.PGDN : gras=0; break;}
      touche=(char)key;   code=key;
      maj = evt.shiftDown(); //touche majuscule enfoncée ?
      repaint();    //pour voir les modifications
      return true;}
}

Utiliser les flèches du clavier pour modifier la taille des caractères et leur couleur

Utiliser les touches PGUP et PGDN pour changer la graisse de la fonte.

 Cliquer dans le cadre de l'applet si elle ne répond pas aux événements clavier.

9.2 Utilisation de la souris

Comme pour la gestion du clavier, la gestion de la souris impose la surcharge des méthodes de la classe Component dédiées à la souris. Ces six méthodes sont les suivantes :
public boolean mouseMove(Event evt, int x, int y) invoquée quand la souris se déplace sans bouton enfoncé.
public boolean mouseDown(Event evt, int x, int y) invoquée quand un bouton de la souris est enfoncé dans la surface de l'applet.
public boolean mouseUp(Event evt, int x, int y)
invoquée quand un bouton de la souris est relâché dans la surface de l'applet.
public boolean mouseDrag(Event evt, int x, int y)
invoquée quand la souris se déplace avec un bouton enfoncé.
public boolean mouseEnter(Event evt, int x, int y)
invoquée quand la souris entre dans la surface de l'applet.
public boolean mouseExit(Event evt, int x, int y) 
invoquée quand la souris sort dans la surface de l'applet.

Ces 6 méthodes possèdent les mêmes arguments : une instance de la classe Event , et les coordonnées (en pixels) du pointeur. Il est inutile de surcharger les méthodes qui ne sont pas utilisées.

Pour rendre JAVA indépendant de la plate-forme utilisée, seule la souris à un bouton est supportée. Toutefois afin de pouvoir utiliser (ou simuler) une souris à deux boutons, la variable d'instance  modifiers de l'objet Event (nommé par exemple evt) peut contenir une valeur de modificateur clavier. Pour les systèmes qui gèrent normalement une  souris à deux boutons, il est possible de tester si le bouton droit est enfoncé avec evt.modifiers== Event.META_MASK .
De même, il est possible de tester si une touche de modification est enfoncée en même temps que le bouton avec evt.modifiers== Event.XXXX_MASK . XXXX correspond à CTRL pour la touche contrôle, SHIFT pour la touche majuscule et META pour la touche Méta .
L'exemple ci-dessous utilise toutes les méthodes de gestion de la souris. Il trace en particulier un réticule qui suit les mouvements du pointeur quand celui-ci est à l'intérieur d'un rectangle. On notera l'utilisation de la méthode r.inside( ) de la classe rectangle qui permet de déterminer simplement si le pointeur de la souris est à l'intérieur d'une zone rectangulaire donnée.
Il est possible de placer le tracé du réticule dans les méthodes mouseDown( ) et mouseDrag( ) mais il faut alors récupérer le contexte graphique avec l'instruction Graphics g = getGraphics( ) ; il est plus simple d'effectuer tous les tracés à partir de la méthode paint( ) en fonction de la valeur d'un booléen.

import java.applet.*;
import java.awt.*;

public class souris0 extends Applet
{  Font font;
    Rectangle r = new Rectangle(20,40,200,80);
    int X,Y; //coordonnées du pointeur
    int z = r.y + 40; //r.y = coordonnée y du coin sup. gauche de r
    boolean actif,droit,dedans,ctrl;

  public void init()
   {  setBackground(Color.lightGray);
      font = new Font("Helvetica",0,11);}

  public void paint(Graphics g)
   {  double t=0;
      g.setColor(Color.black);
      g.drawString("Dedans "+dedans,20,150);
      g.drawString("X = "+X+";  Y = "+Y, 10, 20); //affichage coordonnées pointeur
      g.drawRect(r.x,r.y,r.width,r.height);
      g.setColor(Color.red);
      int yf,yi=(int)(30*Math.sin(t)); //dessin d'une sinusoïde dans le rectangle
      for (int i=r.x; i<r.x+r.width; i++){
         t+=0.05;
         yf=(int)(30*Math.sin(t));
         g.drawLine(i,z-yi,i+1,z-yf);
         yi=yf;}
      if (actif){    //un bouton est enfoncé
         g.setColor(Color.black); //bouton gauche seul
         if (droit) g.setColor(Color.yellow); //bouton droit
         if (ctrl) g.setColor(Color.cyan); //[Ctrl] + bouton gauche
         g.drawLine(X,r.y,X,r.y+r.height); //dessin du réticule
         g.drawLine(r.x,Y,r.x+r.width,Y);}}

   public boolean mouseDown(Event evt, int x, int y)
    {  droit =(evt.modifiers==Event.META_MASK) ? true : false; //test bouton droit
       ctrl =(evt.modifiers==Event.CTRL_MASK) ? true : false;  // [Ctrl] enfoncée
       actif =(r.inside(x,y)) ? true : false; //dans le rectangle ?
       X=x;    Y=y; //récupération des coordonnées du pointeur
       repaint();    //pour voir le résultat
       return true;}

  public boolean mouseUp(Event evt, int x, int y)
   {  actif=false; //si bouton libre => arrêt du tracé du réticule
      repaint();   return true;}

  public boolean mouseDrag(Event evt, int x, int y)
   {  actif =(r.inside(x,y)) ? true : false;
      X=x;    Y=y;   repaint();   return true;}

  public boolean mouseMove(Event evt, int x, int y)
   {  X=x;    Y=y;   repaint();   return true;}

  public boolean mouseExit(Event evt, int x, int y)
   {  dedans=false;  repaint();   return true;}

  public boolean mouseEnter(Event evt, int x, int y)
   { dedans=true;    repaint();   return true;}
}

Cliquer avec le bouton gauche dans le rectangle

Cliquer avec le bouton droit dans le rectangle

Enfoncer la touche [Ctrl] puis cliquer avec le bouton gauche dans le rectangle

 

On peut noter que l'affichage vacille (plus la surface de l'applet est importante plus l'effet est marqué). Ceci est lié au fait que l'on oblige l'applet à se redessiner en permanence lors des mouvements de la souris.
La solution est la même que pour les animations : il faut utiliser un double tampon .
Dans les variables de classe, il faut déclarer par exemple : Image ima;     Graphics h ;
Dans init( ), il faut les créer avec : ima = createImage(size().width,size().height);   h = ima.getGraphics();
Dans paint( ) il faut remplacer toutes les références à g par des références à h.
Dans paint( ) ajouter comme première instruction : h.clearRect(0,0,size().width,size().height);
Dans paint( ) ajouter comme dernière instruction : g.drawImage(ima,0,0,Color.white,this);
Enfin ne pas oublier de surcharger la méthode public void update(Graphics g){paint(g);}
La comparaison des deux applets montre dans ce cas l'intérêt de la technique du double tampon.

 

9.3 Gestion du clavier (Java 1.1.x)

    Pour améliorer (en principe) la fiabilité du fonctionnement, la gestion des événements à été profondément modifiée à partir des versions 1.1.0 de JAVA.
Une applet ne peut répondre au clavier que si on a mis en place la classe KeyListener . Il faut commencer par importer le package java.awt.event.* puis dans l'en-tête ajouter implements KeyListener , dans init( ) il faut ajouter addKeyListener(this) . L'argument this indique que c'est l'applet qui récupère les événements.
Le fait d'ajouter " implements KeyListener", implique que l'on surcharge les trois méthodes keyPressed( ) , keyTyped( )  et keyReleased( ) même si ne souhaite pas utiliser les trois. L'argument de ces méthodes est un objet KeyEvent . L'utilisateur peut récupérer le caractère frappé ou le code de la touche grace aux méthodes getKeyChar( ) , getKeyCode( ) et getModifiers( ) de la classe KeyEvent. Il est préférable de réserver getKeyCode pour récupérer les codes des touches de fonction. Pour simplifier (?) les noms et les valeurs des constantes des touches ont été modifiées par rapport aux versions 1.0.x.

L'exemple ci-dessous exécute les mêmes tâches que l'applet "clavier" du § 9.1. Les principales modifications du code sont indiquées en rouge.

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

public class clavier11 extends Applet implements KeyListener
{  char touche='@';
    int taille=20,code=touche,gras=0,c=125;
    boolean maj;

   public void init()
    {   addKeyListener(this);
       setBackground(Color.lightGray);
       this.requestFocus();}

   public void paint(Graphics g) //inchangée par rapport au code de la version 1.0
    {  Color col = new Color(c,0,0);
       Font font = new Font("Helvetica",gras,taille);
       g.setFont (font);       g.setColor(col);
       g.drawString("taille = "+taille, 10, 60);
       g.drawString("Maj = "+maj, 10, 110);
       g.drawString(String.valueOf(touche)+" => "+code,10,170);}

   public void keyReleased(KeyEvent evt) //ici vide mais obligatoire
    {   }

   public void keyTyped(KeyEvent evt)  
    {  touche= evt.getKeyChar() ;}    //caractère

   public void keyPressed(KeyEvent evt)
    {  int t= evt.getKeyCode() ;     //code touche
       int m= evt.getModifiers() ;   //masque modificateurs clavier
       switch(t){
         case KeyEvent.VK_DOWN : if (taille>6)  taille--;     break;
         case KeyEvent.VK_UP :   if (taille<55) taille++;     break;
         case KeyEvent.VK_LEFT : if (c>0)      c-=5;  break;
         case KeyEvent.VK_RIGHT : if (c<255)  c+=5; break;
         case KeyEvent.VK_PAGE_UP : gras=1; break;
         case KeyEvent.VK_PAGE_DOWN : gras=0; break;}
      code=t; touche=(char)27;
      if ((m & KeyEvent.SHIFT_MASK) != 0) maj=true; else maj=false;
      repaint();}
}

 9.4 Gestion de la souris (Java 1.1.x)

    Une applet ne peut répondre aux événements "souris" que si la classe MouseListener (à l'écoute de la souris) est mise en service par l'ajout dans son en-tête de   implements MouseListener . (Il faut au préalable importer le package java.awt.event.* ). Ceci suppose que l'on surcharge les méthodes mousePressed( ), mouseReleased( ), mouseEntered( ), mouseExited( ) et mouseCliked( ) . Il faut surcharger ces 5 fonctions même si seulement quelques unes sont en fait utilisées. L'argument de ces fonctions est un objet MouseEvent dont les méthodes permettent d'obtenir les informations sur les coordonnées du pointeur, l'objet à l'origine de l'événement ...
Si l'on désire obtenir des informations sur les mouvements de la souris, il faut aussi mettre en oeuvre la classe MouseMoveListener. Il faut alors implémenter les deux méthodes mouseMoved( ) et mouseDragged( ) dont l'argument est également un objet mouseEvent.
La méthode init( ) de l'applet active les "écouteurs" par l'appel aux méthodes addMouseListener(this) et addMouseMotionListener(this) .

Alors que dans les versions 1.0.x, il était pratiquement impossible de modifier la forme du pointeur de la souris, à partir de la version 1.1.0, c'est devenu très simple. Il suffit de déclarer un objet Cursor avec l'instruction Cursor nom  = new Cursor(int c); il existe une série prédéfinie de curseurs. Par exemple la constante Cursor.HAND_CURSOR correspond au curseur en forme de main. L'instruction setCursor(nom) provoque l'affichage de ce pointeur.

L'exemple ci-dessous exécute les mêmes tâches que l'applet "souris" du § 9.2 (version avec double tampon). Les principales modifications du code sont indiquées en rouge.

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

public class souris11 extends Applet implements MouseMotionListener,MouseListener
{  Font font;
    Rectangle r=new Rectangle(20,40,200,80);
    Image ima;      Graphics h;     //double tampon
    int la,ha,X,Y,z=r.y+40,nb;
    boolean actif,droit,dedans,ctrl;
    Cursor main = new Cursor(Cursor.HAND_CURSOR);
    Cursor norm = new Cursor(Cursor.DEFAULT_CURSOR);

   public void init()
    { setBackground(Color.lightGray); 
      font = new Font("Helvetica",0,11);
      la= getSize() .width;       ha=getSize().height; //remplace size() de 1.0.x
      ima=createImage(la,ha);   h=ima.getGraphics();
   addMouseMotionListener(this);
addMouseListener(this); }

   public void update(Graphics g) // double tampon
    {  paint(g);}

   public void paint(Graphics g) // identique à la version 1.0
    {  double t=0;
       h.clearRect(0,0,la,ha);
       h.setColor(Color.black);
       h.drawString("Dedans : "+dedans,20,140);
       h.drawString("X = "+X+";  Y = "+Y, 10, 20);
       h.drawString("nb click = "+nb, 150, 20);
       h.drawRect(r.x,r.y,r.width,r.height);
       h.setColor(Color.red);
       int yf,yi=(int)(30*Math.sin(t));
       for (int i=r.x; i<r.x+r.width; i++){
         t+=0.05;      yf=(int)(30*Math.sin(t));
         h.drawLine(i,z-yi,i+1,z-yf);       yi=yf;}
       if (actif){
         h.setColor(Color.black);
         if (droit) h.setColor(Color.yellow);
         if (ctrl) h.setColor(Color.cyan);
         h.drawLine(X,r.y,X,r.y+r.height);
         h.drawLine(r.x,Y,r.x+r.width,Y);}
       g.drawImage(ima,0,0,Color.white,this);}

  public void mouseReleased(MouseEvent evt) //bouton relâché
   { actif= false;
     setCursor(norm);
     repaint();}        

  public void mousePressed(MouseEvent evt) //bouton pressé
   { int m= evt.getModifiers() ;
     setCursor(main);
     droit=(m == evt.META_MASK) ? true : false; //touche Meta ou bouton droit
     ctrl =((m & evt.CTRL_MASK)!=0) ? true : false;   //touche CTRL
     X= evt.getX() ;   Y=evt.getY();              //coordonnées du pointeur
     actif =(r. contains (X,Y)) ? true : false;   //remplace inside de 1.0.x
     repaint();}

  public void mouseEntered(MouseEvent evt) //entrée du pointeur dans le cadre
   {  dedans=true; repaint();}

  public void mouseExited(MouseEvent evt)   //sortie du cadre
   {  dedans=false; repaint();}

   public void mouseClicked(MouseEvent evt) //pressé puis relaché
   { nb++; repaint();}

   public void mouseMoved(MouseEvent evt)   //déplacement bouton relaché
   { X=evt.getX();   Y=evt.getY(); repaint();}        

  public void mouseDragged(MouseEvent evt) //déplacement bouton pressé
   { X=evt.getX();   Y=evt.getY();
     actif =(r.contains(X,Y)) ? true : false;
     repaint();}
}