Swing
PARTIE 2 : Action !
IntroductionVoici la deuxieme partie du mon tutorial consacré à Swing. Dans la premiere partie, nous avons vu comment ouvrir des fenetres et y placer des composants. C'était un bon début mais il manque un peu de réactivité! En effet, on va voir comment gérer les événements, c'est a dire comment réagir aux differentes interactions avec l'interface. Par exemple, comment traiter le fait que l'utilisateur clique sur un bouton ? etc...
Concepts abordés :-les listeners
-la programmation événementielle
-ActionListener, WindowListener etc...
1. Les ListenersSwing utilise une architecture par événements. En effet, lorsque un composant de l'interface graphique le désire (enfin, lorsque une interaction se produit), il peut provoquer un événement. Un événement est ensuite transmit aux objets qui désirent etre informés de l'événement et réagir en conséquence. Ces objets sont des listeners (des "écouteurs"). Pour définir un listener, il suffit de créer une classe qui implemente une interface de type
EventListener (
http://java.sun.com/j2se/1.5.0/docs/api/java/util/EventListener.html pour voir la liste des listeners disponibles). Ensuite, ce listener devra etre enregistré dans le composant de l'interface graphique dans lequel le listener veut "écouter". Le composant dispatche l'événement à tout ses listeners enregistrés.
2. ActionListener : réagir aux clics sur un JButtonConcrétement, si on veut etre avertit que l'utilisateur clique sur un boutton (JButton), on devra implanter une classe implantant un ActionListener
http://java.sun.com/j2se/1.5.0/docs/api/java/awt/event/ActionListener.html) (un
ActionListener est un
EventListener pour les
JButton) et ajouter ce listener au
JButton.
En pratique :
//création du bouton
JButton but=new JButton("ici");
//Ajout de l'action listener
but.addActionListener(listener);
L'objet listener devra implémenter l'interface
ActionListener : il devra donc obligatoirement contenir la fonction actionPerformed. Cette fonction sera la fonction qui sera appellé lorsqu'un événement se produit sur le bouton
Voici un exemple complet :
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
//le listener est la classe test
public class test extends JFrame implements ActionListener
{
/** Constructeur de test */
public test()
{
//titre de la fenetre
super("Test");
//panel
JPanel pan=new JPanel();
pan.setLayout(new BorderLayout());
//bouton ici
JButton but=new JButton("Ici !");
//ajoute un listener : ici le listener est cette classe
but.addActionListener(this);
//ajoute le boutton dans le panel
pan.add(but,BorderLayout.CENTER);
//
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setContentPane(pan);
pack(); //permet de mettre une bonne dimension a la fenetre
setVisible(true);
}
/**
* obligatoire car test implémente l'interface ActionListener
*/
public void actionPerformed(ActionEvent e)
{
//quand on a cliqué sur le bouton ici
System.out.println("Ici !");
}
public static void main(String args[])
{
new test();
}
}Copiez ce code dans un fichier test.java puis compilez en faisant javac test.java -classpath ".;"
Pour lancez le programme, faites java testDans cet exemple, le listener est la classe elle meme. On respecte bien l'interface ActionListener puisque la fonction actionPerformed est définie. Quand on clique sur le bouton "ici", un message apparait sur la console.
Voici la fenetre obtenue :
Ici dans notre exemple, il y a qu'un seul bouton. Si on met plusieurs boutons, comment les differencier si tout les listeners sont la meme classe ? En effet si on fait le programme suivant :
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class test extends JFrame implements ActionListener
{
private JButton but1,but2; //les boutons
/** Constructeur de test */
public test()
{
//titre de la fenetre
super("Test");
//panel
JPanel pan=new JPanel();
pan.setLayout(new BorderLayout());
//bouton ici
but1=new JButton("Ici !");
//ajoute un listener : ici le listener est cette classe
but1.addActionListener(this);
//ajoute le boutton dans le panel
pan.add(but1,BorderLayout.CENTER);
//2eme Bouton
but2=new JButton("2eme !");
but2.addActionListener(this);
pan.add(but2,BorderLayout.SOUTH);
//
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setContentPane(pan);
pack(); //permet de mettre une bonne dimension a la fenetre
setVisible(true);
}
/**
* obligatoire car test implémente l'interface ActionListener
*/
public void actionPerformed(ActionEvent e)
{
//quand on a cliqué sur le bouton ici
System.out.println("Ici !");
}
public static void main(String args[])
{
new test();
}
}On obtient la fenetre suivante :
Lorsque vous cliquez sur le bouton "ici" et "2eme", on obtient le meme message. C'est normal car ces 2 boutons partagent le meme listener donc le meme gestionnaire d'événement.
2 solutions s'offrent à nous pour pouvoir faire un traitement differents selon les boutons :
-soit on créé deux classes distinctes implémentant un ActionListener qui seront associées a chacun des boutons
-soit en utilisant l'objet ActionEvent passé en parametre de actionPerformed pour différencier les 2 composants.
Nous allons bien sur voir ces 2 solutions !
Solution : Utilisation de ActionEvent A la page http://java.sun.com/j2se/1.5.0/docs/api/java/awt/event/ActionEvent.html on peut voir les méthodes d'un ActionEvent. La fonction getSource() va nous etre utile.
getSource() renvoi le composant qui a provoqué l'événement.
Ainsi, pour différencier le traitement selon le bouton, on réagit en fonction de l'objet retourné par getSource() :
Voici la nouvelle fonction actionPerformed() :
public void actionPerformed(ActionEvent e)
{
Object source=e.getSource();
if (source==but1)
System.out.println("Ici !");
else if (source==but2)
System.out.println("2eme !");
}Maintenant, quand on clique sur le bouton "2eme !", le message affiché est "2eme !". On a différencié les 2 traitements.
La solution de réunir tous les traitement dans le meme listener peut se révéler parfois assez pratique et simple (quoique) mais en mon sens, elle n'est pas trés propre. La solution que nous allons voir aprés est a mon sens bien mieux.
Solution : Une classe par boutonPour différencier le traitement pour nos 2 boutons, nous pouvons créé 2 classes distinctes :
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class test extends JFrame
{
private JButton but1,but2; //les boutons
/** Constructeur de test */
public test()
{
//titre de la fenetre
super("Test");
//panel
JPanel pan=new JPanel();
pan.setLayout(new BorderLayout());
//bouton ici
but1=new JButton("Ici !");
//ajoute un listener : ici le listener est cette classe
but1.addActionListener(new TraitementBut1());
//ajoute le boutton dans le panel
pan.add(but1,BorderLayout.CENTER);
//2eme Bouton
but2=new JButton("2eme !");
but2.addActionListener(new TraitementBut2());
pan.add(but2,BorderLayout.SOUTH);
//
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setContentPane(pan);
pack(); //permet de mettre une bonne dimension a la fenetre
setVisible(true);
}
public static void main(String args[])
{
new test();
}
public class TraitementBut1 implements ActionListener
{
/**
* obligatoire car test implémente l'interface ActionListener
*/
public void actionPerformed(ActionEvent e)
{
System.out.println("Ici !");
}
}
public class TraitementBut2 implements ActionListener
{
/**
* obligatoire car test implémente l'interface ActionListener
*/
public void actionPerformed(ActionEvent e)
{
System.out.println("2eme !");
}
}
}La classe TraitementBut1 gere les événements sur le bouton "ici" et la classe TraitementBut2 sur le bouton "2eme !".
3. Les autres listenersIl existe une énorme varité de listeners pour tout type d'événements. Chaque composant de l'interface graphique a ses événements.
Voici une petite liste des listeners :
WindowListener tout les évenements concernant une fenetre (ouverture, fermeture, selection etc)
MouseListener tout les évenements concernant la souris (clic, etc)
MouseMotionListener tout les évenement concernant le mouvement de la souris
...
Toutes les classes contenant le mot Listener est un listener, regardez la page
http://java.sun.com/j2se/1.5.0/docs/api/ !
4. FinCette deuxieme partie est finie. Vous pouvez m'envoyer vos commentaires/remarques.