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 !
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.
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.
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
evt.VK_DOWN : if (taille>6) taille--; break;
case
evt.VK_UP : if (taille<55) taille++; break;
case
evt.VK_LEFT : if (c>0) c-=5; break;
case
evt.VK_RIGHT : if (c<255) c+=5; break;
case
evt.VK_PAGE_UP : gras=1; break;
case
evt.VK_PAGE_DOWN : gras=0; break;}
code=t; touche=(char)27;
if
((m & evt.SHIFT_MASK) != 0) maj=true; else maj=false;
repaint();}
}
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();}
}