L'Abstract Window Toolkit, l'AWT, est la librairie du JDK 1.0 qui a été la plus touchée
par les modifications introduites par la version 1.1. La gestion des évènements a subi une véritable révolution.
L'ancien système avait de nombreux inconvénients : création de nombreuses classes inutiles, séparation entre l'interface utilisateur et les traitements fonctionnels difficile, mauvaises performances,...
Le nouveau modèle se fonde sur la délégation. Les composants "délèguent" la gestion des évènements utilisateur à une classe extérieure.
Nous avons 3 types d'objets qui effectuent cette gestion :
Il faudra relier chaque source d'évènements à son délégué (qui traîte l'évènement). Concrètement, chaque délégué doit s'enregistrer auprès de sa source. Pour cela, les sources d'évènements définissent des méthodes d'enregistrement du type setTypeEvtListener et addTypeEvtListener.
Mais un exemple va vite clarifier cela :
import java.awt.*; // pour pouvoir accéder à Frame et à Button
import java.awt.event.*; // pour pourvoir accéder à ActionListener
public class IHMSimpliste extends Frame{
public IHMSimpliste() {
Button monBouton = new Button("Tshaw !"); // ajout du bouton à l'interface
// La méthode suivante enregistre le délégué auprès du bouton après l'avoir créé.
// tous les composants standard de l'AWT permettent la diffusion multiple (multi-cast)
// c'est pour cela qu'il n'existe que des méthodes de type addListener.
monBouton.addActionListener(new MonDelegue());
add(monBouton);
}
public static void main(String args[]) { // le point d'entrée
Frame f = new IHMSimpliste(); // on crée la fenêtre
f.pack(); // on l'affiche
f.setVisible(true); //remplace l'ancien show()
}
}
// ceci est la classe déléguée, gérant les événements sur le bouton
class MonDelegue implements ActionListener {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
}
Ceci peut être grandement simplifié grâce aux classes internes :
import java.awt.*; // pour pouvoir accéder à Frame et à Button
import java.awt.event.*; // pour pourvoir accéder à ActionListener
public class IHMSimpliste1 extends Frame{
public IHMSimpliste1() {
Button monBouton = new Button("Tshaw !"); // ajout du bouton à l'interface
monBouton.addActionListener(
// on crée une classe anonyme implémentant ActionListener
new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
}
);
add(monBouton);
}
public static void main(String args[]) { // le point d'entrée
Frame f = new IHMSimpliste1(); // on crée la fenêtre
f.pack(); // on l'affiche
f.setVisible(true); //remplace l'ancien show()
}
}
Dans la pratique, on essaie de séparer encore mieux l'interface utilisateur du code de traitement en utilisant des adaptateurs. Etudiez l'exemple suivant :
import java.awt.*;
import java.awt.event.*;
public class ApplicationSimpliste { // la classe principale est l'application, et sert de délégué.
// elle contient les deux méthodes fonctionnelles
public void quitterAppli() {
System.exit(0);
}
public void maximiser(Frame f){
f.setSize(f.getToolkit().getScreenSize());
}
public static void main(String args[]) {
// on instancie l'application
ApplicationSimpliste monAppli = new ApplicationSimpliste() ;
// on crée l'IHM et on la relie à l'application
IHMSimpliste monIHM = new IHMSimpliste(monAppli) ;
}
}
// cette classe constitue l'IHM de l'application
class IHMSimpliste {
// son constructeur possède comme paramètre l'application à laquelle elle est reliée
public IHMSimpliste(ApplicationSimpliste uneAppli) {
Frame maFrame = new Frame() ;
maFrame.setLayout(new FlowLayout());
// on crée le bouton Quitter
Button monBoutonQuitter = new Button("Tshaw!");
// on lui affecte un adaptateur
monBoutonQuitter.addActionListener(new MonAdaptateur(MonAdaptateur.QUITTER,uneAppli));
// on fait pareil avec le bouton maximiser
Button monBoutonMaximise = new Button("Maximiser");
monBoutonMaximise.addActionListener(new MonAdaptateur(MonAdaptateur.MAXIMISE,uneAppli));
// on ajoute les boutons dans l'interface et on rend la fenêtre visible
maFrame.add(monBoutonQuitter);
maFrame.add(monBoutonMaximise);
maFrame.pack();
maFrame.setVisible(true); //remplace l'ancien show()
}
}
// l'adaptateur effectue l'aiguillage
class MonAdaptateur implements ActionListener {
static final int QUITTER = 1;
static final int MAXIMISE = 2;
protected int typeAction; // l'action affectée à l'adaptateur
protected ApplicationSimpliste lAppli; // le délégué qui va traiter l'action
public MonAdaptateur(int unTypeAction,ApplicationSimpliste uneAppli) {
typeAction = unTypeAction;
lAppli = uneAppli;
}
public void actionPerformed(ActionEvent e) {
// on récupère la fenêtre source de l'événement : on remonte la chaîne
// des composants, jusqu'à trouver une instance de la classe Window
Object unComposant = e.getSource();
do {
unComposant = ((Component) unComposant).getParent();
}
while (!(unComposant instanceof Window));
Window fenetreParente = (Window) unComposant;
switch (typeAction) {
case QUITTER :
// on appelle la méthode quitterAppli du délégué
lAppli.quitterAppli();
break;
case MAXIMISE :
// on appelle la méthode maximiser en passant la Frame
// qui contient le composant sur lequel s'est produit l'événement.
lAppli.maximiser((Frame) fenetreParente);
break;
}
}
}
Consultez les paquetages java.util et java.awt.event pour connaître les différents évènements disponibles.
Enfin, notez qu'il existe des adaptateurs par défauts tels que MouseAdapter qui, en les dérivant, permettent de créer rapidement des adaptateurs sans avoir à implémenter toutes les méthodes de certaines interfaces Listener.