Cours
Programmation Evenementielle
Programmation Evenementielle
2. Les concepts de la programmation événementielle.
2.1.Les principes fondamentaux de l’événementiel
2.2.1.La hiérarchie de classes EventObject
2.2.2.Notion d'événement
2.2.3.Quelques événements
2.2.4.Informations contenues par les événements
2.2.5.Les classes et Interfaces de gestion des évènements
2.2.6.Associer un contrôleur à un composant
2.2.7.Gérer des événements : exemples
2.2.8.Fermer une fenêtre.
2.2.9.Récapitulons
2.2.10.Mettre en œuvre des classes incluses
2.2.11.Inner Class : Classe incluse définie au même niveau que les méthodes
2.2.12.Exercices.
3. L’interface graphique avec AWT.
3.1.Les composants graphiques.
3.1.1.Les étiquettes.
3.1.2.Les boutons.
3.1.3.Les panneaux.
3.1.4.Les listes déroulantes (combobox).
3.1.5.La classe TextComponent.
3.1.7.Les zones de texte multilignes.
3.1.8.Les listes.
3.1.9.Les cases à cocher.
3.1.10.Les barres de défilement.
3.1.11.La classe Canvas.
3.3.1.Le conteneur Panel
3.3.3.Le conteneur Frame.
3.3.4.Le conteneur Dialog.
3.4.Les menus
4. Le développement d'interfaces graphiques avec SWING.
Les composants d'une application événementielle interagissent entre eux et avec l'environnement. Ils communiquent en réponse à des événements. Ces événements peuvent correspondre à une action de l'utilisateur : un click sur un bouton de commande, une écriture dans une zone de texte, un choix dans une case d'option ou une case à cocher, le déplacement d'un objet, ... Ils peuvent aussi être déclenchés par le système : chargement d'une feuille, un top déclenché par l'horloge, ...
Les événements sont captés par le système d'exploitation, sont mis en file d'attente ce qui signifie que les événements sont séquentialisés. Ils sont ensuite pris en charge par la boucle de gestion des événements. La boucle de gestion des événements prend le premier événement à traiter dans la file et la traite. Le traitement consiste en l'exécution des procédures événement associées à celui-ci s'il en existe. C'est le programmeur qui doit prévoir la procédure à exécuter en réponse à un événement donné. Par exemple, le déclenchement de l'événement click sur un bouton quitter doit terminer l'exécution, le choix d'un élément dans un menu doit déclencher certaines opérations, un top d'horloge doit modifier le contenu d'une zone d'image.
Deux packages permettent de gérer les interfaces graphiques : AWT et SWING (intégré à partir de la version 1.2).
AWT utilise des composants lourds, c’est à dire utilisant les ressources du système d’exploitation, alors que Swing utilise des composants dits légers n’utilisant pas ces ressources. Swing est plus robuste que l’AWT, plus portable, et plus facile à utiliser.
Swing ne remplace pas complétement AWT mais fournit des composants d’interface plus performants.
Chaque composant AWT a son équivalent Swing dans le package javax.swing. Nous nous intéresserons surtout aux possibilités développées dans le package swing. (En cours de développement).
Dans le cas de l’événementiel, le programme réagit en fonction d’événements utilisateurs, systèmes ou programmeurs. La façon de coder s’en ressent car le programmeur ne sait pas à l’avance dans quel ordre, certaines actions vont être effectuées.
Le principe général est de recenser les différents événements à traiter et d’écrire pour chacun un gestionnaire d’événements.
Bien que ce mode de programmation concerne un large spectre de logiciels, on se restreindra à la programmation événementielle appliquée aux interfaces graphiques.
Pour de tels problèmes, on sera amené à décomposer la conception et la réalisation en trois parties :
1. Les différents objets graphiques vus par l’utilisateur :
Il s’agit simplement de recenser tous les objets (le mot objet est à prendre dans le sens large non pas dans le sens « langage de programmation ») que l’utilisateur doit voir en fonction de ce qui est dit dans le cahier de charges. On ne se préoccupe pas de la façon de les agencer (phase 2) et de ce qu’on va en faire (phase 3).
a. La fenêtre de fond
Plusieurs applications peuvent tourner en même temps. Toute application graphique est associée à une fenêtre de fond qui permet à l’utilisateur en cliquant dedans de préciser l’application qui passe en avant plan. Elle permet aussi d’iconiser, de désiconiser ou de fermer l’application. Cette fenêtre contiendra tous les autres objets graphiques de l’application.
b. Les barres de menu, les menus et les items de menu
En général, les fenêtres sont attachées à un menu composé de sous menus. Un sou menu est composé d’items de menus ou de sous menus. Un item de menu est associé à un traitement (gestionnaire d’événement).
c. Les textes incrustés ou labels
Cet objet sert à incruster un texte sur l’écran.
d. Les champs de saisie
Cet objet sert pour la saisie par l’utilisateur une information nécessaire au programme. La réponse est libre et non assistée.
e. Les cases à cocher et boutons radio
Ces objets servent pour la saisie par l’utilisateur de valeurs de champs nécessaires au programme. La réponse est fermée. On entend par-là qu’ils permettent simplement de préciser l’absence ou la présence d’une propriété.
f. Les boutons
Ces objets permettent à l’utilisateur de déclencher une action. En ce sens, elle est équivalente à un item de menu. La différence tient au fait qu’ils sont isolés.
g. Les listes pré définies
Ces objets permettent à l’utilisateur de saisir une information. La différence avec un champ de saisie est que ces objets contiennent un ensemble de valeurs pré définies.
h. Les ascenceurs
Ces objet permettent à l’utilisateur à l’aide d’un déplacement de curseur avec la souris d’incrémenter ou de décrémenter un compteur entre deux valeurs limites.
i. Les barres d’outils
Ces objets sont des ensembles de boutons graphiques. Ils servent souvent de raccourci d’item de menu. On entend par-là que l’action associée à chaque bouton est la même que l’action associée à l’un des items du menu.
j. La barre de statut
Elles contiennent un certain nombre de renseignements sur l’état de l’application à tout instant.
k. Les images
Ils permettent de visualiser une image.
l. Les zones de dessin
C’est un objet dans lequel on peut dessiner des formes. Un texte est aussi une forme.
Toute application graphique contient une fenêtre de fond dans laquelle on va poser tous les autres objets graphiques.
Cette fenêtre permet aussi à l’utilisateur de distinguer à l’écran cette application des autres applications en activité.
Lancer l’interface consiste à afficher cette fenêtre. Cet affichage provoque l’affichage de tous les autres objets et par la même occasion le démarrage de l’application pour l’utilisateur.
2. La disposition de ces objets sur l’écran :
Il s’agit dans cette phase de préciser comment on agence à l’écran les différents objets.
En fait cet agencement des objets ne se fait pas dans l’écran mais dans la fenêtre de fond
D’un point de vue général, on place des objets dans des objets. Les objets qui contiennent des objets seront appelés objets conteneur. Quand un objet conteneur est déplacé dans l’écran, alors tous les objets qu’il contient sont déplacés avec lui et leurs placements à l’intérieur du conteneur ne change pas.
3. Les différents événements à traiter sur chaque objet graphique et les écouteurs associés :
On s’intéresse à la gestion des futurs événements provoqués par l’utilisateur.
Il faut pour chaque objet graphique recensé dans la phase1 :
Recenser les différents événements à traiter sur cet objet en fonction de ce qui est dit dans le cahier de charges.
Pour chaque événement, définir l’action à réaliser que l’on appellera le gestionnaire d’événement.
Les classes de cette hiérarchie encapsulent les événements qui se produisent notamment dans une interface graphique. Il s'agit, par exemple, d’un clic souri, de la frappe d’une touche ou du changement de la taille d’une fenêtre.
Lorsque l’on développe une interface graphique, on a besoin d’écouter les messages que l’utilisateur envoie à l’interface, on doit permettre à l’interface de gérer les événements provoqués par l’utilisateur (clavier, souris) et par le système d’exploitation (horloge).
Les événements que l’on va traiter vont générer des actions sur l’interface, on des traitements spécifiques.
En Java, les événements n'ont pas une valeur physique mais logique.
Par exemple, un clic souri ne correspond pas toujours à l'émission d'un événement de type MouseEvent. L'événement émis suite à un clic de souris dépend du composant sur lequel est fait ce clic.
Composant Evénement émis
Canevas (Canvas) MouseEvent
Liste (List) ItemEvent
Bouton (Button), Menu (MenuItem) ActionEvent
Il existe des évènements de bas niveau qui permettent par exemple de savoir si le bouton droit de la souris est enfoncé, relaché, si la souris a bougé, ou si une touche particulière est enfoncée ou relachée, si un composant vient d'être activé (Focus)...
De bas niveau :
FocusEvent : prise et perte de focus,
KeyEvent, MouseEvent : événements clavier ou souris.
il existe aussi des évènements de haut niveau, qui sont activées dés qu'il y a n'importe quel type d'action (clavier ou souris) sur un composant.
De haut niveau :
ActionEvent : action spécifique à un composant (clic bouton, sélection d’un menu...),
TextEvent : changement de valeur d’un champ de saisie.
Les événements sont capables de fournir des informations concernant leur contexte d’apparition.
MouseEvent : position de la souris,
KeyEvent : valeur de la touche enfoncée, etc.
La même action sur des composants différents ne provoque pas le même événement.
Un clic gauche sur :un bouton,une liste,une zone de saisie ne provoque pas le même événement.
Certains événements transportent des informations :
Un caractère saisi au clavier provoque l’événement keyEvent qui transmet par son paramètre le caractère effectivement saisi au clavier
Intercepter des événements
Chaque composant ne gère pas forcément lui-même les événements qu’il génère. Il délègue cette gestion à des objets particuliers : les contrôleurs (appelés aussi listener).
Les interfaces de type EventListener
En fonction des événements qu’ils gèrent, les contrôleurs doivent implémenter des interfaces de la hiérarchie EventListener.
Les Interfaces bas Niveaux : Exemples
Ex. : l’interface MouseMotionListener gère le déplacement de la souris :
public interface MouseMotionListener extends EventListener {
// interface définissant les fonctions à associer au déplacement de la souris
public void mouseMoved(MouseEvent e);
// appelé lors du déplacement de la souris
public void mouseDragged(MouseEvent e);
// appelé lors du déplacement de la souris, clic gauche enfoncé
}
Ex. : l’interface MouseListener gère les opérations statiques de la souris :
public interface MouseListener extends EventListener {
public void mouseClicked(MouseEvent e);
public void mouseEntered(MouseEvent e)
public void mouseExited(MouseEvent e);
public void mousePressed(MouseEvent e);
public void mouseReleased(MouseEvent e);
}
Ex. : l’interface KeyListener gère les opérations sur le clavier :
public interface KeyListener extends EventListener {
public void keyPressed(KeyEvent e);
public void keyReleased(KeyEvent e);
public void keyTyped(KeyEvent e);
}
Les Interfaces haut Niveaux : Exemple
Ex. : l’interface ActionListener gère tout type d'opération sur le composant
public interface ActionListener extends EventListener {
public void actionPerformed(ActionEvent e);
}
Les méthodes définies dans les interfaces seront appelées à l’émission d’un événement. A ce moment, un objet événement est passé en paramètre. Son type dépend de l’interface associée.
Exemple1 : Utilisation de ActionEvent
Le but de ce programme est d'afficher la phrase entrée dans un TextField dans la console à chaque fois que l'on tape RETOUR CHARRIOT
pour cela , il faut créer un objet texte de la classe TextField. Puis , grace à la méthode addActionListener lui associé la classe de gestion de l'évènement. Cette classe de gestion de l'évènement doit obligatoirement implémenté les méthodes de l'interface ActionListener. Dans cette interface, il ne faut redéfinir qu'une seule méthode, la méthode actionPerformed. Le code de cette méthode sera appélé à chaque fois, que l'on tapera la touche Entrée. Le Système nous passe en argument de la fonction actionPerformed, une référence sur un objet de la classe ActionEvent. Cette classe possède plusieurs méthodes, et notamment la méthode getText () qui permet de renvoyer la chaine écrite dans le TexteField.
import java.awt.*;
import java.awt.event.*;
public class EssaiEvenement extends Frame{
public EssaiEvenement(String s) {
super(s);
TextField text = new TextField(20);
GestionEv gestion = new GestionEv();
text.addActionListener(gestion);
setSize(200,200);
setLayout(new FlowLayout());
add(text);
show();
}
public static void main(java.lang.String[] args) {
EssaiEvenement e= new EssaiEvenement("EssaiEvenement");
e.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e) {System.exit(0);}
});
}
}
import java.awt.event.*;
public class GestionEv implements ActionListener{
public void actionPerformed(ActionEvent e){
System.out.println(e.getActionCommand());
}
}
Récapitulatif
Si on ajoute l’instruction addActionListener, cela signifie que le composant peut être source d’événements de type ActionEvent.
Le paramètre indique qui gère ces événements. (càd qui est le contrôleur)
addActionListener (ActionListener l) : permet d’intercepter le clic de la souris sur le bouton.
addComponentListener(ComponentListener l) : permet d’intercepter tous les événements relatifs aux classes dérivées de Composant.
addFocusListener(FocusListener l) permet de gérer la prise et la perte du focus sur le composant
addKeyListener(KeyListener l) permet de détecter l’appuie sur une touche.
addMouseListener(MouseListener l) permet l’interception de tous les événements liés à la souris.
addMouseMotionListener(MouseMotionListener l) : gestion des mouvements de la souris.
Tous les composants susceptibles d’émettre des événements possèdent des méthodes du type addXXXListener, où XXX représente une interface de la hiérarchie EventListener.
Exemple: la classe Button et ses gestionnaires
Tous les composants ne gère pas les mêmes évènements, il faut regarder dans la documentation sun, les EventListener associés
public void addActionListener(ActionListener l)
public void addComponentListener(ComponentListener l)
public void addFocusListener(FocusListener l)
public void addKeyListener(KeyListener l)
public void addMouseListener(MouseListener l)
public void addMouseMotionListener(MouseMotionListener l)
Première version
Le but du programme est à chaque fois que l'utilisateur tape un caractère, celui-ci est affiché dans le titre de la fenêtre. Remarque : pour utiliser la méthode setTitle de la fenêtre, il faut obligatoirement passeer la référence de la fenêtre à la classe GereTexte. Ainis le constructeur de la classe GereText recoit en argument une référence de la classe frame.
import java.awt.*; import java.awt.event.*;
class FenetreTitre extends Frame {
public FenetreTitre() {
TextField texte = new TextField();
add(texte, "North");
texte.addTextListener(new GereTexte(this));
show();
}
}
class GereTexte implements TextListener {
private Frame f;
public GereTexte(Frame fenetre) {
f = fenetre;
}
public void textValueChanged(TextEvent e) {
TextField source = (TextField) e.getSource();
f.setTitle(source.getText());
}
}
Principe
textValueChanged(TextEvent e) est la seule méthode de l’interface TextListener.
(l’interface TextListener hérite de l’interface EventListener du package java.util)
intérêt de cette première version : GereTexte est réutilisable. C'est ce qui a été utilisé dans le premier exemple.
Deuxième version
Version plus simple. Dans ce cas la classe FenêtreTitre implémente directement l'interface TextListener
MAIS :
non réutilisable : si on veut avoir ce comportement pour une fenêtre qui n’est pas de la classe fenêtre-titre, il faut tout recoder.
import java.awt.*; import java.awt.event.*;
class FenetreTitre extends Frame implements TextListener {
private TextField texte;
public FenetreTitre() {
add(texte = new TextField(), "North");
texte.addTextListener(this);
show();
}
public void textValueChanged(TextEvent e) {
setTitle(texte.getText());
}
}
Ici, l'interface TextListener est implémentée par le composant lui-même.
Résultat des deux versions
Utilisation des contrôleurs prédéfinis
Nous avons jusqu'à présent utiliser dans la fonction main le code suivant :
public static void main(java.lang.String[] args) {
EssaiEvenement e= new EssaiEvenement("EssaiEvenement");
e.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e) {System.exit(0);}
});
}
Ce code nous permettait de fermer l'application, lorsqu'on appuyait sur la croix de fermeture de la fenêtre.
Le fait de fermer une fenêtre est un événement qui est émis par une instance de Frame.
Il faut associer à cet événement un comportement : pour nous, ce sera arrêter l’application.
Il faut tout d’abord rechercher la méthode du type addXXXListener qui permet de signaler que notre classe est susceptible d’émettre tel ou tel événement. "addWindowListener"
L’interface WindowListener indique toutes les méthodes qui peuvent être reçues par une fenêtre.
Ces méthodes sont abstraites : si on veut que notre fenêtre implémente cette interface, il faut redéfinir toutes ces méthodes....
public interface WindowListener extends EventListener {
public void windowOpened(WindowEvent e);
public void windowClosing(WindowEvent e);
public void windowClosed(WindowEvent e);
public void windowIconified(WindowEvent e);
public void windowDeiconified(WindowEvent e);
public void windowActivated(WindowEvent e);
public void windowDeactivated(WindowEvent e);
}
SOLUTION 1 :
On créé une classe Essai1 qui implémente directement l'interface WindowListener
Il faut implémentéer toutes les méthodes de l'interface WindowListener
package coursawt;
import java.awt.*;
import java.awt.color.*;
import java.awt.event.*;
public class Essai1 extends Frame implements WindowListener {
public Essai1() {
super();
}
public Essai1(String title) {
super(title);
addWindowListener(this);
show();
}
public static void main(java.lang.String[] args) {
new Essai1("Essai1");
}
public void windowActivated(WindowEvent e) {}
public void windowClosed(WindowEvent e) {}
public void windowClosing(WindowEvent e) {System.exit(0);}
public void windowDeactivated(WindowEvent e) {}
public void windowDeiconified(WindowEvent e) {}
public void windowIconified(WindowEvent e) {}
public void windowOpened(WindowEvent e) {}
}
Exercice : Une autre solution
Ecrire la classe GestionFermeture qui implémente les méthodes de l'interface WindowListener, puis utiliser cette classe dans la classe Essai2 pour fermer la fenêtre
Les classes Adapter
Pour chaque interface XXXListener, il existe une classe XXXAdapter, qui implémente toutes les méthodes de cette interface.
Il nous suffit donc de redéfinir seulement les méthodes dont on a besoin.
(Remarque : il n’existe pas d’Adapter lorsque l’interface n’a qu’une méthode)
Remarque :
windowClosing : appelée lorsqu’on clique sur la case système de fermeture de la fenêtre.
windowClosed : appelée après la fermeture de la fenêtre. N’a de sens que si la fermeture de la fenêtre n’entraîne pas la fin de l’application.
La classe Frame hérite la méthode addWindowListener définie dans la classe Window.
Cette méthode prend en paramètre un objet de type WindowListener.
Pour fermer une fenêtre, nous devons seulement implémenter la méthode windowClosing.
import java.awt.*; import java.awt.event.*;
public class FrameFerme extends Frame{
public FrameFerme (){
super("Fenêtre");
addWindowListener(new GereFermeture());
show();
}
}
class GereFermeture extends WindowAdapter {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}
En cherchant à gérer le clic souris sur une applet (classe Applet) pour afficher les coordonnées, regardons quelles sont les étapes à suivre :
Choix entre MouseListener et MouseAdapter :
si on va utiliser + de 90% des comportements : Listener
si on va utiliser - de 10% des comportements : Adapter
Rechercher les méthodes de type addXXXListener définies dans la classe du composant ou une de ses classes mères.
Pour la classe Applet, il existe cinq méthodes :
addContainerListener(ContainerListener)
addComponentListener(ComponentListener)
addFocusListener(FocusListener)
addKeyListener(KeyListener)
addMouseListener(MouseListener)
addMouseMotionListener(MouseMotionListener)
Identifier le contrôleur qui nous intéresse en inspectant les méthodes qu'il définit. L'interface MouseListener définit cinq méthodes dont la méthode mouseClicked(MouseEvent e) convient.
Définir une classe qui implémente cette interface (Cette classe peut être le composant lui-même.) ou qui dérive d’une classe qui implémente cette interface.Trouver une classe qui implémente cette interface (l'adapteur de l'interface XXXListener a comme nom XXXAdapter)
Nous utiliserons pour notre canevas l'adapteur MouseAdapter.
Implémenter la méthode retenue (ici, mouseClicked) en exploitant les informations contenues dans l'événement passé en paramètre.
public class AppletClic extends Applet {
public void init() {
addMouseListener(new GereClic());
}
}
class GereClic extends MouseAdapter {
public void mouseClicked(MouseEvent e) {
System.out.println(e.getX() + " , " + e.getY());
}
}
Où gérer les événements ?
Dans le composant,
Il faut alors que le composant implémente l'interface adéquate. Cela permet d’encapsuler les méthodes associées à l’événement dans l’objet Component.
Dans une classe indépendante,
cette classe doit, elle aussi, implémenter l'interface adéquate, éventuellement en la dérivant d'une classe adapteur. Ceci permet de bien séparer les composants des traitements qui leur sont associés.
Dans plusieurs contrôleurs,
Button bouton = new Button("Ok");
bouton.addActionListener(new GereBoutonClic());
// gère l'aspect du bouton
bouton.addActionListener(new GereFermetureFenetre());
// gère la fermeture de la fenêtre contenant le bouton
... etc
Lorsque l'on appuiera sur le bouton Ok, les méthodes actionPerformed de GereBoutonClic et de GereFermetureFenetre seront appelées.
Ceci permet d'associer plusieurs types de réaction à un événement. Dans l'exemple précédent, la classe GereBoutonClic gère l'aspect du bouton après le clic (traitement étroitement lié à l'interface graphique) et la classe GereFermetureFenetre vérifie si toutes les conditions sont remplies pour fermer la fenêtre (traitement lié à la logique de l'application).
Exercices :
On désire faire le programme ci-dessous. Le bouton Fermeture permet de fermer la fenêtre (même fonction que la croix de fermeture), le bouton changer Couleur permet de changer la couleur du fond de la fenêtre, et lorsqu'on tape dans la zone d'édition, celle-ci est automatiquement copié dans un label.
Ecrire le programme de 2 façons :
La classe MesDebuts utilise une classe par évènement,
La classe MesDebuts utilise une classe Gestion qui gère tous les évènements. Dans ce cas, le code de la classe Gestion sera le suivant
class Gestion implements ActionListener{
public void actionPerformed(ActionEvent e){
if(e.getSource()==bFermeture) // Fermeture
if(e.getSource()==bChangerCouleur) // ChangerCouleur
if(e.getSource()==texte) // mettre à jour Label
}
}
Les « inner classes » sont une caractéristique fondamentale du langage Java depuis le JDK1.1. Il est possible d’imbriquer des définitions de classes les unes dans les autres avec différentes sémantiques.
Les classes incluses sont souvent utilisées dans la gestion des événements des interfaces graphiques. Dans l’exemple de la modification du titre d’une fenêtre par un champ de saisie, on peut décliner plusieurs écritures :
Dans l’exemple :
FenetreTitre.this. setTitle(FenetreTitre.this.texte.getText());
a le même effet que :
setTitle(texte.getText());
Par contre, si la méthode setTitle, ou bien la variable d’instance texte existait dans la classe incluse GereTexte, ca ne marche plus.
Par exemple, si GereTexte héritait aussi de Frame, la méthode setTitle s’appliquerait à l’objet courant de la classe GereTexte !
public class FenetreTitre extends Frame{
private TextField text;
public FenetreTitre(){
text = new TextField();
add(text,"North");
text.addTextListener(new GereTexte());
show();
}
private class GereTexte implements TextListener{
public void textValueChanged(TextEvent e){
setTitle(text.getText());
}
}
}
Dans ce cas, setTitle s’applique à l’objet de la classe GereTexte. Par contre, la variable texte est celle de l’objet FenetreTitre (car le compilateur n’a trouvé aucune variable de ce nom dans GereTexte).
Conclusion :
Dès qu’on tape quelque chose dans le champ de saisie de la fenêtre FenetreTitre, c’est le titre de la fenêtre GereTexte qui est modifié.
Un objet GereTexte ne peut exister que dans un objet FenetreTitre
Dans la méthode textValueChanged de la classe incluse GereTexte, la référence désignant l’objet courant de la classe englobante FenetreTitre, s’écrira FenetreTitre.this (ne pas confondre avec une variable de classe).
Ici, cette référence peut être omise. En effet, le compilateur recherche d’abord si une méthode existe dans la classe incluse, puis, si elle n’y est pas, il appelle celle de la classe englobante.
Une classe incluse peut aussi être définie à l’intérieur d’une méthode.
La classe GereTexte n’étant utilisée qu’une seule fois, il est possible de la définir directement à l’endroit où une instance de cette classe est nécessaire.
L’anonymat n’est pas réel. A la compilation, on trouve dans le repertoire / package des fichiers de byte-code correspondant à ces classes « anonymes » suivant une désignation particulière à la manière des classes incluses non anonymes.
Il n’est pas nécessaire d’en parler sauf très brièvement si une question précise est posée.
On peut indiquer par contre que pour une classe incluse CI dans une méthode M :
Si CI utilise des variables locales (y compris les paramètres formels) de M, ces variables locales doivent impérativement être final sinon erreur de compilation est générée.
Classes incluses anonymes
Classe incluse anonyme implémentant une interface
class FenetreTitre extends Frame {
private TextField texte = new TextField(); ;
public FenetreTitre() {
add(texte, "North");
texte.addTextListener(
new TextListener() {
public void textValueChanged(TextEvent e) {
setTitle(texte.getText());
}
}//fin classe incluse anonyme
);//fin addTextListener
}//fin constructeur FenetreTitre
}//fin classe FenetreTitre
new TextListener(){...} renvoie la référence d’un objet créé dont la classe :
est « anonyme »,
dérive de Object,
implémente l’interface TextListener,
ne dispose que du constructeur par défaut.
Classe incluse anonyme héritant d’une superclasse
public class FrameFerme extends Frame{
public FrameFerme (){
super("Fenêtre");
addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}//fin classe incluse anonyme
);//fin addWindowListener
}//fin constructeur FrameFerme
}//fin classe FrameFerme
Cette classe anonyme a pour superclasse WindowAdapter et ne peut implémenter aucune interface.
Ecrire un programme qui permet de donner la position de la souris et son état . Ceci sera affiché dans une Label placer au sud de la fenêtre (BorderLayout).
Ecrire un programme qui utilise une liste déroulante (Choice) pour ajouter des items dans un Choice, il suffit d'utiliser la méthode addItem(item) de la classe Choice. Pour permettre , la gestion de l'évènement associé au Choice, il faut utiliser la méthode addItemListener(ItemListener l) de Choice.
A chaque fois que l'utilisateur fera un choix dans la liste, le choix sera affiché dans un Label.
Ecrire un Programme qui permet d'afficher les touches de fonctions appuyées. Pour cela on utilisera addKeyListener(KeyListener l) et la méthode
keyPressed(KeyEvent e) {switch(e.getKeyCode()){
case e.VK_F1:// touche F1 enfoncé
case e.VK_F2 // touche F2 enfoncé
...
}
Ecrire une machine à calculer : pour cela on utilisera les touche de 0 à 9 et les fonction +,-,*,/,CE,=,.,bin,hex. On pourra se servir de l'interface graphique faite au chapitre précédent. On pourra gérer les exceptions.
Les classes du toolkit AWT (Abstract Windows Toolkit) permettent d’écrire des interfaces graphiques indépendantes du système d’exploitation sur lesquelles elles vont fonctionner. Cette librairie utilise le système graphique de la plateforme d’exécution (Windows, MacOS, X-Window) pour afficher les objets graphiques. Le toolkit contient des classes décrivant les composants graphiques, les polices, les couleurs et les images.
Le diagramme ci dessus définit une vue partielle de la hiérarchie des classes (les relations d’héritage) qu’il ne faut pas confondre avec la hiérarchie interne à chaque application qui définit l’imbrication des différents composants graphiques.
Les deux classes principales de AWT sont Component et Container. Chaque type d’objet de l’interface graphique est une classe dérivée de Component. La classe Container, qui hérite de Component est capable de contenir d’autres objets graphiques (tout objet dérivant de Component).
Ce chapitre contient plusieurs sections :
Les composants graphiques
La classe Component
Les conteneurs
Les menus
Pour utiliser un composant, il faut créer un nouvel objet représentant le composant et l’ajouter à un de type conteneur qui existe avec la méthode add().
import java.applet.*;
import java.awt.*;
public class AppletButton extends Applet {
Button b = new Button(“ Bouton “);
public void init() {
super.init();
add(b);
}
}
Label la = new Label( );
la.setText(« une etiquette »);
// ou Label la = new Label(« une etiquette »);
Il est possible de créer un objet de la classe java.awt.Label en précisant l’alignement du texte
Label la = new Label(« etiquette », Label.RIGHT);
Le texte à afficher et l’alignement peuvent être modifiés dynamiquement lors de l’éxecution :
la.setText(« nouveau texte »);
la.setAlignment(Label.LEFT);
Il faut utiliser un objet de la classe java.awt.Button
Cette classe possède deux constructeurs :
Constructeur Rôle
Button()
Button(String) Permet de préciser le libellé du bouton
Button bouton = new Button();
bouton.setLabel(“bouton”);
// ou Button bouton = new Button(« bouton »);
Le libellé du bouton peut être modifié dynamiquement grace à la méthode setLabel() :
bouton.setLabel(« nouveau libellé »);
Les panneaux sont des conteneurs qui permettent de rassembler des composants et de les positionner grace à un gestionnaire de présentation. Il faut utiliser un objet de la classe java.awt.Panel.
Par défaut le gestionnaire de présentation d’un panel est de type FlowLayout.
Constructeur Role
Panel() Créer un panneau avec un gestionnaire de présentation de type FlowLayout
Panel(LayoutManager) Créer un panneau avec le gestionnaire précisé en paramètre
Panel p = new Panel();
L’ajout d’un composant au panel se fait grace à la méthode add().
p.add(new Button(“bouton”);
Il faut utiliser un objet de la classe java.awt.Choice
Cette classe ne possède qu’un seul constructeur qui ne possèdent pas de paramètres.
Choice maCombo = new Choice();
Les méthodes add() et addItem() permettent d’ajouter des éléments à la combo.
maCombo.addItem(« element 1 »);
// ou maCombo.add(« element 2 »);
Plusieurs méthodes permettent la gestion des sélections :
Méthodes Role
void select( int ); sélectionner un élément par son indice : le premier élément correspond à l’indice 0.
Une exception IllegalArgumentException est levée si l’indice ne correspond pas à un
élément.
maCombo.select(0);
void select( String); sélectionner un élément par son contenu
Aucune exception est levée si la chaîne de caractères ne correspond à aucun élément : l’élément sélectionné ne change pas.
maCombo.select("element 1");
int countItems( ); déterminer le nombre d’élément de la liste. La méthode countItems() permet d’obtenir le nombre d’éléments de la combo.
int n;
n=maCombo.countItems();
int n;
n=maCombo.getItemCount();
String getItem( int ); lire le contenu de l’élément d’indice n
String c = new String( );
c = maCombo.getItem(n);
String getSelectedItem(); déterminer le contenu de l’élément sélectionné
String s = new String( );
s = maCombo.getSelectedItem();
int getSelectedIndex( ); déterminer l’index de l’élément selectionné
int n;
n=maCombo.getSelectedIndex();
La classe TextComponent est la classe des mères des classes qui permettent l’édition de texte : TextArea et TextField.
Elle définit un certain nombre de méthodes dont ces classes héritent.
Méthodes Role
String getSelectedText( ); Renvoie le texte sélectionné
int getSelectionStart( ); Renvoie la position de début de sélection
int getSelectionEnd( ); Renvoie la position de fin de sélection
String getText( ); Renvoie le texte contenu dans l’objet
boolean isEditable( ); Retourne un booleen indiquant si le texte est modifiable
void select(int start, int end ); Sélection des caractères situés entre start et end
void selectAll( ); Sélection de tout le texte
void setEditable(boolean b); Autoriser ou interdire la modification du texte
void setText(String s ); Définir un nouveau texte
Il faut déclarer un objet de la classe java.awt.TextField
Il existe plusieurs constructeurs :
Constructeurs Role
TextField();
TextField( int ); prédetermination du nombre de caractères à saisir
TextField( String ); avec texte par défaut
TextField( String, int ); avec texte par défaut et nombre de caractères à saisir
Cette classe possède quelques méthodes utiles :
Méthodes Role
String getText( ) lecture de la chaîne saisie
String saisie = new String();
saisie = tf.getText( );
int getColumns( ) lecture du nombre de caractères predéfini
int i;
i = tf.getColumns( );
void setEchoCharacter() pour la saisie d’un mot de passe : remplace chaque caractère saisi par celui fourni en paramètre
tf.setEchoCharacter(‘*’);
TextField tf = new TextField(10);
tf.setEchoChar(‘*’);
Il faut déclarer un objet de la classe java.awt.TextArea
Il existe plusieurs constructeurs :
Constructeur Role
TextArea()
TextArea( int, int ) avec prédetermination du nombre de lignes et de colonnes
TextArea( String ) avec texte par défaut
TextArea( String, int, int ) avec texte par défaut et taille
Les principales méthodes sont :
Méthodes Role
String getText() lecture du contenu intégral de la zone de texte
String contenu = new String;
contenu = ta.getText( );
String getSelectedText( ) lecture de la portion de texte sélectionnée
String contenu = new String;
contenu = ta.getSelectedText( );
int getRows() détermination du nombre de lignes
int n;
n = ta.getRows( );
int getColumns( ) détermination du nombre de colonnes
int n;
n = ta.getColumns( );
void insertText(String, int) insertion de la chaîne à la position fournie
String text =
new String(«texte inséré»);
int n =10;
ta.insertText(text,n);
String text = new
String(«texte inséré»);
int n =10;
ta.insert(text,n);
void setEditable(boolean) Autoriser la modification
ta.setEditable(False);
//texte non modifiable
void appendText(String) Ajouter le texte transmis au texte existant
ta.appendTexte(String text);
void replaceText(String, int, int) Remplacer par text le texte entre les positions start et end
ta.replaceText(text, 10, 20);
Il faut déclarer un objet de la classe java.awt.List.
Il existe plusieurs constructeurs :
Constructeur Role
List( )
List( int ) Permet de préciser le nombre de lignes affichées
List( int, boolean ) Permet de préciser le nombre de lignes affichées et l’indicateur de sélection multiple
Les principales méthodes sont :
Méthodes Role
void addItem(String) ajouter un élément
li.addItem(« nouvel element »); // a jout en fin de liste
void addItem(String, int) insérer un élément à un certain emplacement : le premier element est en position 0
li.addItem(« ajout ligne »,2);
void delItem(int) retirer un élément de la liste
li.delItem(0); // supprime le premier element
void delItems(int, int) supprimer plusieurs éléments consécutifs entre les deux indices
li.delItems(1, 3);
void clear() effacement complet du contenu de la liste
li.clear( );
void replaceItem(String, int) remplacer un élément
li.replaceItem(« ligne remplacee »,1);
int countItems() nombre d’élément de la liste
int n;
n = li.countItems( );
int getRows() nombre de ligne de la liste
int n;
n = li.getRows( );
String getItem(int) contenu d’un élément
String text = new String( );
text = li.getItem(1);
void select(int) sélectionner un élément
li.select(0);
setMultipleSelections(boolean) déterminer si la sélection multiple est autorisée
li.setMultipleSelections(true);
void deselect(int) désélectionner un élément
li.deselect(0);
int getSelectedIndex( ) déterminer l’élément sélectionné en cas de selection simple : renvoie l’indice ou -1 si aucun élément n’est sélectionné
int i;
i = li.getSelectedIndex();
int[] getSelectedIndexes( ) déterminer les éléments sélectionnées en cas de sélection multiple
int i[]=li.getSelectedIndexes();
String getSelectedItem( ) déterminer le contenu en cas de sélection simple : renvoie le texte ou null si pas de sélection
String texte = new String( );
texte = li.getSelectedItem( );
String[] getSelectedItems() déterminer les contenus des éléments sélectionnés en cas de sélection multiple : renvoie les textes sélectionnés ou null si pas de sélection
String texte[ ] =li.getSelectedItems();
for (i = 0 ; i <texte.length(); i++)
System.out.println(texte[i]);
boolean isSelected(int) déterminer si un élément est sélectionné
boolean selection;
selection = li.isSelected(0);
int getVisibleIndex() renvoie l’index de l’entrée en haut de la liste
int top = li.getVisibleIndex();
void makeVisible(int) assure que l’élement précisé sera visible
li.makeVisible(10);
Exemple:
import java.awt.*;
class TestList {
static public void main (String arg [ ]) {
Frame frame = new Frame(“Une liste”);
List list = new List(5,true);
list.add(“element 0”);
list.add(“element 1”);
list.add(“element 2”);
list.add(“element 3”);
list.add(“element 4”);
frame.add(List);
frame.show();
frame.pack();
}
}
Il faut déclarer un objet de la classe java.awt.Checkbox
Il existe plusieurs constructeurs :
Méthodes Role
void setLabel(String) modifier l’étiquette
cb.setLabel("libelle de la case :");
void setState( boolean ) fixer l’état
cb.setState( true );
boolean getState( ) consulter l’état de la case
boolean etat;
etat = cb.getState( );
String getLabel( ) lire l’étiquette de la case
String commentaire = new String( );
commentaire = cb.getLabel( );
Déclarer un objet de la classe java.awt.CheckboxGroup
CheckboxGroup rb;
Checkbox cb1 = new Checkbox(« etiquette 1 », rb, etat1_boolean);
Checkbox cb2 = new Checkbox(« etiquette 2 », rb, etat1_boolean);
Checkbox cb3 = new Checkbox(« etiquette 3 », rb, etat1_boolean);
Les principales méthodes sont :
Méthodes Role
Checkbox getCurrent() retourne l’objet Checkbox correspondant à la réponse sélectionnée
il faut utiliser la méthode getSelectedCheckbox()
void setCurrent(Checkbox) Coche le bouton radio passé en paramètre
il faut utiliser la méthode setSelectedCheckbox()
Constructeur Role
Checkbox( )
Checkbox( String) avec une étiquette
Checkbox( String,boolean) avec une étiquette et un état
Checkbox(String,CheckboxGroup, boolean) avec une étiquette, dans un groupe de cases à cocher et un état
Il faut déclarer un objet de la classe java.awt.Scrollbar
Il existe plusieurs constructeurs :
Constructeur
Scrollbar( )
Scrollbar(orientation)
Scrollbar( orientation, valeur_initiale, visible, min, max )
Orientation : Scrollbar.VERTICALE ou Scrollbar.HORIZONTAL
valeur_initiale : position du curseur à la création
visible : taille de la partie visible de la zone défilante
min : valeur minimale associée à la barre
max : valeur maximale associée à la barre
Les principales méthodes sont :
Méthodes Role
sb.setValues(int,int,int,int ) maj des parametres de la barre
sb.setValues(valeur,visible,min,max);
void setValue(int) modifer la valeur courante
sb.setValue(10);
int getMaximum( ); lecture du maximum
int max =sb.getMaximum( );
int getMinimum( ); lecture du minimum
int min =sb.getMinimum( );
int getOrientation( ) lecture de l’orientation
int o =sb.getOrientation( );
int getValue( ); lecture de la valeure courante
int valeur =sb.getValue( );
void setLineIncrement( int ); détermine la valeur à ajouter ou à oter quand l’utilisateur clique sur une flèche de défilement
int setPageIncrement( ); détermine la valeur à ajouter ou à oter quand l’utilisateur clique sur le conteneur
C’est un composant sans fonction particulière : il est utile pour créer des composants graphiques personnalisés.
Il est nécessaire d’étendre la classe Canvas pour en redéfinir la méthode Paint().
import java.awt.*;
public class MonCanvas extends Canvas {
public void paint(Graphics g) {
g.setColor(Color.black);
g.fillRect(10, 10, 100,50);
g.setColor(Color.green);
g.fillOval(40, 40, 10,10);
}
}
import java.applet.*;
import java.awt.*;
public class AppletButton extends Applet {
MonCanvas mc = new MonCanvas();
public void paint(Graphics g) {
super.paint(g);
mc.paint(g);
}
}
Les contrôles fenêtrés descendent plus ou moins directement de la classe AWT Component.
Cette classe contient de nombreuse méthodes : Affiche tableau des methode
Les conteneurs sont des objets graphiques qui peuvent contenir d’autres objets graphiques, incluant éventuellement des conteneurs. Ils héritent de la classe Container.
Un composant graphique doit toujours être incorporé dans un conteneur :
Conteneur Rôle
Panel conteneur sans fenêtre propre. Utile pour ordonner les contrôles Window fenêtre principale sans cadre ni menu. Les objets descendants de cette classe peuvent servir à implémenter des menus
Dialog (descendant de Window) réaliser des boîtes de dialogue simples
Frame (descendant de Window) classe de fenêtre completement fonctionnelle
Applet (descendant de Panel) pas de menu. Pas de boîte de dialogue sans être incorporée dans une classe Frame.
L’insertion de composant dans un conteneur se fait grace à la méthode add(Component) de la classe Container.
Panel p = new Panel();
Button b1 = new button(« premier »);
p.add(b1);
Button b2;
p.add(b2 = new Button (« Deuxième »);
p.add(new Button(«Troisième »);
C’est essentiellement un objet de rangement pour d’autres composants.
La classe Panel possède deux constructeurs :
Constructeur Role
Panel()
Panel(LayoutManager) Permet de préciser un layout manager
Panel p = new Panel( );
Button b = new Button(« bouton »);
p.add( b);
La classe Window contient plusieurs méthodes dont voici les plus utiles :
Méthodes Role
void pack() Calculer la taille et la position de tous les contrôles de la fenêtre. La méthode pack() agit en étroite collaboration avec le layout manager et permet à chaque contrôle de garder, dans un premier temps sa taille optimale. Une fois que tous les contrôles ont leur taille optimale, pack() utilise ces informations pour positionner les contrôles. pack() calcule ensuite la taille de la fenêtre. L’appel à pack() doit se faire à l’intérieur du constructeur de fenêtre après insertion de tous les contrôles.
void show() Afficher la fenêtre
Utiliser setVisible(true/false)
void dispose() Liberer les ressources allouée à la fenêtre
Ce conteneur permet de créer des fenêtres d’encadrement. Il hérite de la classe Window qui ne s’occupe que de l’ouverture de la fenêtre. Window ne connait pas les menus ni les bordures qui sont gérés par la classe Frame. Dans une applet, elle n’apparait pas dans le navigateur mais comme une fenêtre indépendante.
Il existe deux constructeurs :
Constructeur Role
Frame() Exemple : Frame f = new Frame( );
Frame(String) Precise le nom de la fenêtre
Exemple : Frame f = new Frame("titre");
Les principales méthodes sont :
Méthodes Role
setCursor(int) changer le pointeur de la souris dans la fenêtre
Exemple : f.setCursor(Frame.CROSSHAIR_CURSOR);
utiliser la méthode setCursor(Cursor).
int getCursorType() Déterminer la forme actuelle du curseur
utiliser la méthode getCursor().
Image getIconImage() déterminer l’icone actuelle de la fenêtre
MenuBar getMenuBar() déterminer la barre de menus actuelle
String getTitle() déterminer le titre de la fenêtre
boolean isResizeable() déteriner si la taille est modifiable
void remove(MenuComponent) Supprimer un menu
void setIconImage(Image); définir l’icone de la fenêtre
void setMenuBar(MenuBar) Définir la barre de menu
void setResizeable(boolean) définir si la taille peut être modifiée
void SetTitle(String) définir le titre de la fenêtre
import java.applet.*;
import java.awt.*;
public class AppletFrame extends Applet {
Frame f;
public void init() {
super.init();
// insert code to initialize the applet here
f = new Frame(“titre”);
f.add(new Label(“hello “));
f.show();
f.setSize(300, 100);
}
}
Le message « Warning : Applet window » est impossible à enlever dans la fenêtre : cela permet d’éviter la création d’une applet qui demande un mot de passe.
Le gestionnaire de mise en page par défaut d’une Frame est BorderLayout (FlowLayout pour une applet).
import java.awt.*;
public class MaFrame extends Frame {
public MaFrame() {
super();
setTitle(« Titre de la Fenetre « );
setSize(300, 150);
show(); // affiche la fenetre
}
public static void main(String[] args) {
new MaFrame();
}
}
La classe Dialog hérite de la classe Window.
Une boîte de dialogue doit dérivée de la Classe Dialog de package java.awt.
Un objet de la classe Dialog doit dépendre d’un objet de la classe Frame.
import java.awt.*;
import java.awt.event.*;
public class Apropos extends Dialog {
public APropos(Frame parent) {
super(parent, “A propos “, true);
addWindowListener(new
AProposListener(this));
setSize(300, 300);
setResizable(False);
}
}
class AProposListener extends WindowAdapter {
Dialog dialogue;
public AProposListener(Dialog dialogue) {
this.dialogue = dialog;
}
public void windowClosing(WindowEvent e) {
dialogue.dispose();
}
}
L’appel du constructeur Dialog(Frame, String, Boolean) permet de créer une instance avec comme paramètres : la fenêtre à laquelle appartient la boîte de dialogue, le titre de la boîte, le caractère modale de la boîte.
La méthode dispose() de la classe Dialog qui ferme la boîte et libère les ressources associées. Il ne faut pas associer cette action à la méthode windowClosed() car dispose provoque l’appel de windowClosed ce qui entrainerait un appel récursif infini.
Il faut insérer les menus dans des objets de la classe Frame (fenêtre d’encadrement). Il n’est donc pas possible d’insérer directement des menus dans un applet.
Il faut créer une barre de menu et l’affecter à la fenêtre d’encadrement. Il faut ensuite créer les entrées de chaque menu et les rattacher à la barre. Ajouter ensuite les éléments à chacun des menus.
import java.awt.*;
public class MaFrame extends Frame {
public MaFrame() {
super();
setTitle(« Titre de la Fenetre « );
setSize(300, 150);
MenuBar mb = new MenuBar();
setMenuBar(mb);
Menu m = new Menu(« un menu « );
mb.add(m);
m.add(new MenuItem(“ 1er element “));
m.add(new MenuItem(“ 2eme element “));
Menu m2 = new Menu(« sous menu « );
CheckboxMenuItem cbm1 = new CheckboxMenuItem(“ menu item 1.3.1 “);
m2.add(cbm1);
cbm1.setState(true);
CheckboxMenuItem cbm2 = new CheckboxMenuItem(“ menu item 1.3.2 “);
m2.add(cbm2);
m.add(m2);
pack();
show(); // affiche la fenetre
}
public static void main(String[] args) {
new MaFrame();
}
}
--------------------------------------------------------------------------------------------------
import java.awt.*;
public class MenuFenetre extends java.awt.MenuBar {
public MenuItem menuQuitter, menuNouveau, menuApropos;
public MenuFenetre() {
Menu menuFichier = new Menu("Fichier");
menuNouveau = new MenuItem("Nouveau" );
menuQuitter = new MenuItem("Quitter" );
menuFichier.add(menuNouveau);
menuFichier.addSeparator();
menuFichier.add(menuQuitter);
Menu menuAide = new Menu(« Aide « );
menuApropos = new MenuItem(« A propos « );
menuAide.add(menuApropos);
add(menuFichier);
setHelpMenu(menuAide);
}
}
La méthode setHelpMenu() confère sous certaines plateformes un comportement particulier à ce menu.
La méthode setMenuBar() de la classe Frame prend en paramètre une instance de la classe MenuBar. Cette instance peut être directement une instance de la classe MenuBar qui aura été modifiée grace aux méthodes add() ou alors une classe dérivée de MenuBar qui est adaptée aux besoins (voir Exemple);
import java.awt.*;
public class MaFrame extends Frame {
public MaFrame() {
super();
setTitle("Titre de la Fenetre");
setSize(300, 150);
MenuFenetre mf = new
MenuFenetre();
setMenuBar(mf);
pack();
setVisible(true); // affiche la fenetre
}
public static void main(String[] args) {
new MaFrame();
}
}
Les méthodes de la classe MenuBar
Méthodes Role
void add(Menu) ajouter un menu dans la barre
int countMenus() renvoie le nombre de menus
utiliser la méthode getMenuCount().
Menu getMenu(int pos) renvoie le menu à la position spécifiée
void remove(int pos) supprimer le menu à la position spécifiée
void remove(Menu) supprimer le menu de la barre de menu
Les méthodes de la classe Menu
Méthodes Role
MenuItem add(MenuItem) ajouter une option dans le menu
void add(String)
void addSeparator() ajouter un trait de séparation dans le menu
int countItems() renvoie le nombre d’options du menu
utiliser la méthode getItemCount().
MenuItem getItem(int pos) déterminer l’option du menu à la position spécifiée
void remove(MenuItem mi) supprimer la commande spécifiée
void remove(int pos) supprimer la commande à la position spécifiée
Les méthodes de la classe MenuItem
Méthodes Role
void disable() désactiver l’élément
utiliser la méthode setEnabled(false).
void enable() activer l’élément
utiliser la méthode setEnabled(true).
void enable(boolean cond) désactiver ou activer l’élément en fonction du paramètre
utiliser la méthode setEnabled(boolean).
String getLabel() Renvoie le texte de l’élément
boolean isEnabled() renvoie l’état de l’élément (actif / inactif)
void setLabel(String text) définir une nouveau texte pour la commande
Les méthodes de la classe CheckboxMenuItem
Méthodes Role
boolean getState() renvoie l’état d’activation de l’élément
Void setState(boolean) définir l’état d’activation de l’élément
Plan
4.Le développement d'interfaces graphiques avec SWING
4.3.Un exemple de fenêtre autonome
4.4.2.Les étiquettes : la classe JLabel
4.4.3.Les panneaux : la classe Jpanel
4.5.1.La classe AbstractButton
4.5.5.Les cases à cocher : la classe JCheckBox
4.5.6.Les boutons radio : la classe JRadioButton
4.6.Les composants de saisie de texte
4.6.1.La classe JTextComponent
4.6.3.La classe JPasswordField
4.6.4.La classe JFormattedTextField
4.7.Le composant JTable
4.7.1.Utilisation simple d’une JTable
4.7.2.Renderers par défaut
4.7.3.Les Editors
4.8.Les gestionnaires de présentation
4.8.1.Exemple de GridLayout
4.9.Les onglets
4.10.Le composant JTree
4.10.1.La création d'une instance de la classe JTree
4.10.2.La gestion des données de l'arbre
4.10.3.La modification du contenu de l'arbre
4.10.4.La mise en oeuvre d'actions sur l'arbre
4.10.5.La gestion des événements
4.10.6.La personnalisation du rendu
Swing fait partie de la bibliothèque Java Foundation Classes (JFC). C'est une API dont le but est similaire à celui de l'API AWT mais dont le mode de fonctionnement et d'utilisation est complètement différent. Swing a été intégrée au JDK depuis sa version 1.2. Cette bibliothèque existe séparément pour le JDK 1.1.
La bibliothèque JFC contient :
l'API Swing : de nouvelles classes et interfaces pour construire des interfaces graphiques
Accessibility API :
2D API: support du graphisme en 2D
API pour l'impression et le cliquer/glisser
Ce chapitre contient plusieurs sections :
Présentation de Swing
Les packages Swing
Un exemple de fenêtre autonome
Les composants Swing
Les boutons
Les composants de saisie de texte
Les onglets
Le composant JTree
Swing propose de nombreux composants dont certains possèdent des fonctions étendues, une utilisation des mécanismes de gestion d'événements performants (ceux introduits par le JDK 1.1) et une apparence modifiable à la volée (une interface graphique qui emploie le style du système d'exploitation Windows ou Motif ou un nouveau style spécifique à Java nommé Metal).
Tous les éléments de Swing font partie d'un package qui a changé plusieurs fois de nom : le nom du package dépend de la version du J.D.K. utilisée :
com.sun.java.swing : jusqu'à la version 1.1 beta 2 de Swing, de la version 1.1 des JFC et de la version 1.2 beta 4 du J.D.K.
java.awt.swing : utilisé par le J.D.K. 1.2 beta 2 et 3
javax.swing : à partir des versions de Swing 1.1 beta 3 et J.D.K. 1.2 RC1
Les composants Swing forment un nouvelle hériarchie parallèle à celle de l'AWT. L'ancêtre de cette hiérarchie est le composant JComponent. Presque tous ces composants sont écrits en pur Java : ils ne possèdent aucune partie native sauf ceux qui assurent l'interface avec le système d'exploitation : JApplet, JDialog, JFrame, et JWindow. Cela permet aux composants de toujours avoir la même apparence quelque soit le système sur lequel l'application s'exécute.
Tous les composants Swing possèdent les caractéristiques suivantes :
ce sont des beans
ce sont des composants légers (pas de partie native) hormis quelques exceptions.
leurs bords peuvent être changés
La procédure à suivre pour utiliser un composant Swing est identique à celle des composants de la bibliothèque AWT : créer le composant en appelant son constructeur, appeler les méthodes du composant si nécessaire pour le personnaliser et l'ajouter dans un conteneur.
Swing utilise la même infrastructure de classes que AWT, ce qui permet de mélanger des composants Swing et AWT dans la même interface. Sun recommande toutefois d'éviter de les mélanger car certains peuvent ne pas être restitués correctement.
Les composants Swing utilisent des modèles pour contenir leurs états ou leur données. Ces modèles sont des classes particulières qui possèdent toutes un comportement par défaut.
Swing contient plusieurs packages :
javax.swing package principal : il contient les interfaces, les principaux composants, les modèles par défaut
javax.swing.border Classes représentant les bordures
javax.swing.colorchooser Classes définissant un composant pour la sélection de couleurs
javax.swing.event Classes et interfaces pour les événements spécifiques à Swing. Les autres événements sont ceux de AWT (java.awt.event)
javax.swing.filechooser Classes définissant un composant pour la sélection de fichiers
javax.swing.plaf Classes et interfaces génériques pour gérer l'apparence
javax.swing.plaf.basic Classes et interfaces de base pour gérer l'apparence
javax.swing.plaf.metal Classes et interfaces pour définir l'apparence Metal qui est l'apparence par défaut
javax.swing.table Classes définissant un composant pour la présentation de données sous forme de tableau
javax.swing.text Classes et interfaces de bases pour les composants manipulant du texte
javax.swing.text.html Classes permettant le support du format HTML
javax.swing.text.html.parser Classes permettant d'analyser des données au format HTML
javax.swing.text.rtf Classes permettant le support du format RTF
javax.swing.tree Classes définissant un composant pour la présentation de données sous forme d'arbre
javax.swing.undo Classes permettant d'implémenter les fonctions annuler/refaire
La classe de base d'une application est la classe JFrame. Son rôle est équivalent à la classe Frame de l'AWT et elle s'utilise de la même façon.
import javax.swing.*;
import java.awt.event.*;
public class swing1 extends JFrame {
public swing1() {
super("titre de l'application");
WindowListener l = new WindowAdapter() {
public void windowClosing(WindowEvent e){
System.exit(0);
}
};
addWindowListener(l);
setSize(200,100);
setVisible(true);
}
public static void main(String [] args){
JFrame frame = new swing1();
}
}
Il existe des composants Swing équivalents pour chacun des composants AWT avec des constructeurs semblables. De nombreux constructeurs acceptent comme argument un objet de type Icon, qui représente une petite image généralement stockée au format Gif.
Le constructeur d'un objet Icon admet comme seul paramètre le nom ou l'URL d'un fichier graphique
import javax.swing.*;
import java.awt.event.*;
public class swing3 extends JFrame {
public swing3() {
super("titre de l'application");
WindowListener l = new WindowAdapter() {
public void windowClosing(WindowEvent e){
System.exit(0);
}
};
addWindowListener(l);
ImageIcon img = new ImageIcon("tips.gif");
JButton bouton = new JButton("Mon bouton",img);
JPanel panneau = new JPanel();
panneau.add(bouton);
setContentPane(panneau);
setSize(200,100);
setVisible(true);
}
public static void main(String [] args){
JFrame frame = new swing3();
}
}
JFrame est l'équivalent de la classe Frame de l'AWT : les principales différences sont l'utilisation du double buffering qui améliore les rafraîchissements et l'utilisation d'un panneau de contenu (contentPane) pour insérer des composants (ils ne sont plus insérés directement au JFrame mais à l'objet contentPane qui lui est associé). Elle représente une fenêtre principale qui possède un titre, une taille modifiable et éventuellement un menu.
La classe possède plusieurs constructeurs :
Constructeur Rôle
JFrame()
JFrame(String) Création d'une instance en précisant le titre
Par défaut, la fenêtre créée n'est pas visible. La méthode setVisible() permet de l'afficher.
import javax.swing.*;
public class TestJFrame1 {
public static void main(String argv[]) {
JFrame f = new JFrame("ma fenetre");
f.setSize(300,100);
f.setVisible(true);
}
}
La gestion des événements est identique à celle utilisée dans l'AWT depuis le J.D.K. 1.1.
import javax.swing.*;
import java.awt.event.*;
public class swing2 extends JFrame {
public swing2() {
super("titre de l'application");
WindowListener l = new WindowAdapter() {
public void windowClosing(WindowEvent e){
System.exit(0);
}
};
addWindowListener(l);
JButton bouton = new JButton("Mon bouton");
JPanel panneau = new JPanel();
panneau.add(bouton);
setContentPane(panneau);
setSize(200,100);
setVisible(true);
}
public static void main(String [] args){
JFrame frame = new swing2();
}
}
Tous les composants associés à un objet JFrame sont gérés par un objet de la classe JRootPane. Un objet JRootPane contient plusieurs Panes. Tous les composants ajoutés au JFame doivent être ajoutés à un des Pane du JRootPane et non au JFrame directement. C'est aussi à un de ces Panes qu'il faut associer un layout manager si nécessaire.
Le Pane le plus utilisé est le ContentPane. Le Layout manager par défaut du contentPane est BorderLayout. Il est possible de le changer :
f.getContentPane().setLayout(new FlowLayout());
import javax.swing.*;
public class TestJFrame2 {
public static void main(String argv[]) {
JFrame f = new JFrame("ma fenetre");
f.setSize(300,100);
JButton b =new JButton("Mon bouton");
f.getContentPane().add(b);
f.setVisible(true);
}
}
Le JRootPane se compose de plusieurs éléments :
glassPane : un JPanel par défaut
layeredPane qui se compose du contentPane (un JPanel par défaut) et du menuBar (un objet de type JMenuBar)
Le glassPane est un JPanel transparent qui se situe au dessus du layeredPane. Le glassPane peut être n'importe quel composant : pour le modifier il faut utiliser la méthode setGlassPane() en fournissant le composant en paramètre.
Le layeredPane regroupe le contentPane et le menuBar.
Le contentPane est par défaut un JPanel opaque dont le gestionnaire de présentation est un BorderLayout. Ce panel peut être remplacé par n'importe quel composant grâce à la méthode setContentPane().
Remarque
Attention : il ne faut pas utiliser directement la méthode setLayout() d'un objet JFrame sinon une exception est levée.
import javax.swing.*;
import java.awt.*;
public class TestJFrame7 {
public static void main(String argv[]) {
JFrame f = new JFrame("ma fenetre");
f.setLayout(new FlowLayout());
f.setSize(300,100);
f.setVisible(true);
}
}
C:\swing\code>java TestJFrame7
Exception in thread "main" java.lang.Error: Do not use javax.swing.JFrame.setLay
out() use javax.swing.JFrame.getContentPane().setLayout() instead
at javax.swing.JFrame.createRootPaneException(Unknown Source)
at javax.swing.JFrame.setLayout(Unknown Source)
at TestJFrame7.main(TestJFrame7.java:8)
Le menuBar permet d'attacher un menu à la JFrame. Par défaut, le menuBar est vide. La méthode setJMenuBar() permet d'affecter un menu à la JFrame.
import javax.swing.*;
import java.awt.*;
public class TestJFrame6 {
public static void main(String argv[]) {
JFrame f = new JFrame("ma fenetre");
f.setSize(300,100);
JButton b =new JButton("Mon bouton");
f.getContentPane().add(b);
JMenuBar menuBar = new JMenuBar();
f.setJMenuBar(menuBar);
JMenu menu = new JMenu("Fichier");
menu.add(menuItem);
menuBar.add(menu);
f.setVisible(true);
}
}
Il est possible de préciser comment un objet JFrame, JInternalFrame, ou JDialog réagit à sa fermeture grâce à la méthode setDefaultCloseOperation(). Cette méthode attend en paramètre une valeur qui peut être :
Constante Rôle
WindowConstants.DISPOSE_ON_CLOSE détruit la fenêtre
WindowConstants.DO_NOTHING_ON_CLOSE rend le bouton de fermeture inactif
WindowConstants.HIDE_ON_CLOSE cache la fenêtre
Cette méthode ne permet pas d'associer d'autres traitements. Dans ce cas, il faut intercepter l'évenement et lui associer les traitements.
import javax.swing.*;
public class TestJFrame3 {
public static void main(String argv[]) {
JFrame f = new JFrame("ma fenetre");
f.setSize(300,100);
JButton b =new JButton("Mon bouton");
f.getContentPane().add(b);
f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
f.setVisible(true);
}
}
La méthode setIconImage() permet de modifier l'icône de la JFrame.
import javax.swing.*;
public class TestJFrame4 {
public static void main(String argv[]) {
JFrame f = new JFrame("ma fenetre");
f.setSize(300,100);
JButton b =new JButton("Mon bouton");
f.getContentPane().add(b);
f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
ImageIcon image = new ImageIcon("book.gif");
f.setIconImage(image.getImage());
f.setVisible(true);
}
}
Si l'image n'est pas trouvée, alors l'icône est vide. Si l'image est trop grande, elle est redimensionnée.
Par défaut, une JFrame est affichée dans le coin supérieur gauche de l'écran. Pour la centrer dans l'écran, il faut procéder comme pour une Frame : déterminer la position de la Frame en fonction de sa dimension et de celle de l'écran et utiliser la méthode setLocation() pour affecter cette position.
import javax.swing.*;
import java.awt.*;
public class TestJFrame5 {
public static void main(String argv[]) {
JFrame f = new JFrame("ma fenetre");
f.setSize(300,100);
JButton b =new JButton("Mon bouton");
f.getContentPane().add(b);
f.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
f.setLocation(dim.width/2 - f.getWidth()/2, dim.height/2 - f.getHeight()/2);
f.setVisible(true);
}
}
La gestion des évenements associés à un objet JFrame est identique à celle utilisée pour un objet de type Frame de AWT.
import javax.swing.*;
import java.awt.event.*;
public class TestJFrame8 {
public static void main(String argv[]) {
JFrame f = new JFrame("ma fenetre");
f.setSize(300,100);
f.setVisible(true);
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}
);
}
}
Le composant JLabel propose les mêmes fonctionnalités que les intitulés AWT mais ils peuvent en plus contenir des icônes .
Cette classe possède plusieurs constructeurs :
Constructeurs Rôle
JLabel() Création d'une instance sans texte ni image
JLabel(Icon) Création d'une instance en précisant l'image
JLabel(Icon, int) Création d'une instance en précisant l'image et l'alignement horizontal
JLabel(String) Création d'une instance en précisant le texte
JLabel(String, Icon, int) Création d'une instance en précisant le texte, l'image et l'alignement horizontal
JLabel(String, int) Création d'une instance en précisant le texte et l'alignement horizontal
Le composant JLabel permet d'afficher un texte et/ou une icône en précisant leur alignement. L'icône doit être au format GIF et peut être une animation dans ce format.
import javax.swing.*;
import java.awt.*;
public class TestJLabel1 {
public static void main(String argv[]) {
JFrame f = new JFrame("ma fenetre");
f.setSize(100,200);
JPanel pannel = new JPanel();
JLabel jLabel1 =new JLabel("Mon texte dans JLabel");
pannel.add(jLabel1);
ImageIcon icone = new ImageIcon("book.gif");
JLabel jLabel2 =new JLabel(icone);
pannel.add(jLabel2);
JLabel jLabel3 =new JLabel("Mon texte",icone,SwingConstants.LEFT);
pannel.add(jLabel3);
f.getContentPane().add(pannel);
f.setVisible(true);
}
}
La classe JLabel définit plusieurs méthodes pour modifier l'apparence du composant :
Méthodes Rôle
setText() Permet d'initialiser ou de modifier le texte affiché
setOpaque() Indique si le composant est transparent (paramètre false) ou opaque (true)
setBackground() Indique la couleur de fond du composant (setOpaque doit être à true)
setFont() Permet de préciser la police du texte
setForeGround() Permet de préciser la couleur du texte
setHorizontalAlignment() Permet de modifier l'alignement horizontal du texte et de l'icône
setVerticalAlignment() Permet de modifier l'alignement vertical du texte et de l'icône
setHorizontalTextAlignment() Permet de modifier l'alignement horizontal du texte uniquement
setVerticalTextAlignment() Permet de modifier l'alignement vertical du texte uniquement
Exemple :
jLabel.setVerticalTextPosition(SwingConstants.TOP);
setIcon() Permet d'assigner une icône
setDisabledIcon() Permet d'assigner une icône dans un état désactivée
L'alignement vertical par défaut d'un JLabel est centré. L'alignement horizontal par défaut est soit à droite si il ne contient que du texte, soit centré si il contient un image avec ou sans texte. Pour modifier cet alignement, il suffit d'utiliser les méthodes ci dessus en utilisant des constantes en paramètres : SwingConstants.LEFT, SwingConstants.CENTER, SwingConstants.RIGHT, SwingConstants.TOP, SwingConstants.BOTTOM
Par défaut, un JLabel est transparent : son fond n'est pas dessiné. Pour le dessiner, il faut utiliser la méthode setOpaque() :
import javax.swing.*;
import java.awt.*;
public class TestJLabel2 {
public static void main(String argv[]) {
JFrame f = new JFrame("ma fenetre");
f.setSize(100,200);
JPanel pannel = new JPanel();
JLabel jLabel1 =new JLabel("Mon texte dans JLabel 1");
jLabel1.setBackground(Color.red);
pannel.add(jLabel1);
JLabel jLabel2 =new JLabel("Mon texte dans JLabel 2");
jLabel2.setBackground(Color.red);
jLabel2.setOpaque(true);
pannel.add(jLabel2);
f.getContentPane().add(pannel);
f.setVisible(true);
}
}
Dans l'exemple, les 2 JLabel ont le fond rouge demandé par la méthode setBackground(). Seul le deuxième affiche un fond rouge car il est rendu opaque avec la méthode setOpaque().
Il est possible d'associer un raccourci clavier au JLabel qui permet de donner le focus à un autre composant. La méthode setDisplayedMnemonic() permet de définir le raccourci clavier. Celui ci sera activé en utilisant la touche Alt avec le caractère fourni en paramètre. La méthode setLabelFor() permet d'associer le composant fourni en paramètre au raccourci.
import javax.swing.*;
import java.awt.*;
public class TestJLabel3 {
public static void main(String argv[]) {
JFrame f = new JFrame("ma fenetre");
f.setSize(300,100);
JPanel pannel = new JPanel();
JButton bouton = new JButton("saisir");
pannel.add(bouton);
JTextField jEdit = new JTextField("votre nom");
JLabel jLabel1 =new JLabel("Nom : ");
jLabel1.setBackground(Color.red);
jLabel1.setDisplayedMnemonic('n');
jLabel1.setLabelFor(jEdit);
pannel.add(jLabel1);
pannel.add(jEdit);
f.getContentPane().add(pannel);
f.setVisible(true);
}
}
Dans l'exemple, à l'ouverture de la fenêtre, le focus est sur le bouton. Un appui sur Alt+'n' donne le focus au champ de saisie.
La classe JPanel est un conteneur utilisé pour regrouper et organiser des composants grâce à un gestionnaire de présentation (layout manager). Le gestionnaire par défaut d'un JPanel est un objet de la classe FlowLayout.
Il existe plusieurs boutons définis par Swing.
C'est une classe abstraite dont hérite les boutons Swing JButton, JMenuItem et JToggleButton.
Cette classe définit de nombreuses méthodes dont les principales sont :
Méthode Rôle
AddActionListener Associer un écouteur sur un évenement de type ActionEvent
AddChangeListener Associer un écouteur sur un évenement de type ChangeEvent
AddItemListener Associer un écouteur sur un évenement de type ItemEvent
doClick() Déclencher un clic par programmation
getText() Obtenir le texte affiché par le composant
setDisabledIcon() Associer une icône affichée lorsque le composant à l'état désélectionné
setDisabledSelectedIcon() Associer une icône affichée lors du passage de la souris sur le composant à l'état désélectionné
setEnabled() Activer/désactiver le composant
setMnemonic() Associer un raccourci clavier
setPressedIcon() Associer une icône affichée lorsque le composant est cliqué
setRolloverIcon() Associer une icône affichée lors du passage de la souris sur le composant
setRolloverSelectedIcon() Associer une icône affichée lors du passage de la souris sur le composant à l'état sélectionné
setSelectedIcon() Associer une icône affichée lorsque le composant à l'état sélectionné
setText() Mettre à jour le texte du composant
isSelected() Indiquer si le composant est dans l'état sélectionné
setSelected() Mettre à jour l'état sélectionné du composant
Tous les boutons peuvent afficher du texte et/ou une image.
Il est possible de préciser une image différente lors du passage de la souris sur le composant et lors de l'enfoncement du bouton : dans ce cas, il faut créer trois images pour chacun des états (normal, enfoncé et survolé). L'image normale est associée au bouton grâce au constructeur, l'image enfoncée grâce à la méthode setPressedIcon() et l'image lors d'un survole grâce à la méthode setRolloverIcon(). Il suffit enfin d'appeler la méthode setRolloverEnable() avec en paramètre la valeur true.
import javax.swing.*;
import java.awt.event.*;
public class swing4 extends JFrame {
public swing4() {
super("titre de l'application");
WindowListener l = new WindowAdapter() {
public void windowClosing(WindowEvent e){
System.exit(0);
}
};
addWindowListener(l);
ImageIcon imageNormale = new ImageIcon("arrow.gif");
ImageIcon imagePassage = new ImageIcon("arrowr.gif");
ImageIcon imageEnfoncee = new ImageIcon("arrowy.gif");
JButton bouton = new JButton("Mon bouton",imageNormale);
bouton.setPressedIcon(imageEnfoncee);
bouton.setRolloverIcon(imagePassage);
bouton.setRolloverEnabled(true);
getContentPane().add(bouton, "Center");
JPanel panneau = new JPanel();
panneau.add(bouton);
setContentPane(panneau);
setSize(200,100);
setVisible(true);
}
public static void main(String [] args){
JFrame frame = new swing4();
}
}
Un bouton peut recevoir des évenements de type ActionEvents (le bouton a été activé), ChangeEvents, et ItemEvents.
import javax.swing.*;
import java.awt.event.*;
public class TestJButton3 {
public static void main(String argv[]) {
JFrame f = new JFrame("ma fenetre");
f.setSize(300,100);
JPanel pannel = new JPanel();
JButton bouton1 = new JButton("Bouton1");
bouton1.addActionListener( new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
}
);
pannel.add(bouton1);
f.getContentPane().add(pannel);
f.setVisible(true);
}
}
Pour de plus amplements informations sur la gestion des événements, voir le chapitre correspondant.
JButton est un composant qui représente un bouton : il peut contenir un texte et/ou une icône.
Les constructeurs sont :
Constructeur Rôle
JButton()
JButton(String) préciser le texte du bouton
JButton(Icon) préciser une icône
JButton(String, Icon) préciser un texte et une icone
Il ne gère pas d'état. Toutes les indications concernant le contenu du composant JLabel sont valables pour le composant JButton.
import javax.swing.*;
import java.awt.event.*;
public class swing3 extends JFrame {
public swing3() {
super("titre de l'application");
WindowListener l = new WindowAdapter() {
public void windowClosing(WindowEvent e){
System.exit(0);
}
};
addWindowListener(l);
ImageIcon img = new ImageIcon("tips.gif");
JButton bouton = new JButton("Mon bouton",img);
JPanel panneau = new JPanel();
panneau.add(bouton);
setContentPane(panneau);
setSize(200,100);
setVisible(true);
}
public static void main(String [] args){
JFrame frame = new swing3();
}
}
L'image gif peut être une animation.
Dans un conteneur de type JRootPane, il est possible de définir un bouton par défaut grace à sa méthode setDefaultButton().
import javax.swing.*;
import java.awt.*;
public class TestJButton2 {
public static void main(String argv[]) {
JFrame f = new JFrame("ma fenetre");
f.setSize(300,100);
JPanel pannel = new JPanel();
JButton bouton1 = new JButton("Bouton 1");
pannel.add(bouton1);
JButton bouton2 = new JButton("Bouton 2");
pannel.add(bouton2);
JButton bouton3 = new JButton("Bouton 3");
pannel.add(bouton3);
f.getContentPane().add(pannel);
f.getRootPane().setDefaultButton(bouton3);
f.setVisible(true);
}
}
Le bouton par défaut est activé par un appui sur la touche Entrée alors que le bouton actif est activé par un appui sur la barre d'espace.
La méthode isDefaultButton() de JButton permet de savoir si le composant est le bouton par défaut.
Cette classe définit un bouton à deux états : c'est la classe mère des composants JCheckBox et JRadioButton.
La méthode setSelected() héritée de AbstractButton permet de mettre à jour l'état du bouton. La méthode isSelected() permet de connaître cet état.
La classe ButtonGroup permet de gérer un ensemble de boutons en garantissant qu'un seul bouton du groupe sera sélectionné.
Pour utiliser la classe ButtonGroup, il suffit d'instancier un objet et d'ajouter des boutons (objets héritant de la classe AbstractButton) grâce à la méthode add(). Il est préférable d'utiliser des objets de la classe JToggleButton ou d'une de ces classes filles car elles sont capables de gérer leurs états.
import javax.swing.*;
public class TestGroupButton1 {
public static void main(String argv[]) {
JFrame f = new JFrame("ma fenetre");
f.setSize(300,100);
JPanel pannel = new JPanel();
ButtonGroup groupe = new ButtonGroup();
JRadioButton bouton1 = new JRadioButton("Bouton 1");
groupe.add(bouton1);
pannel.add(bouton1);
JRadioButton bouton2 = new JRadioButton("Bouton 2");
groupe.add(bouton2);
pannel.add(bouton2);
JRadioButton bouton3 = new JRadioButton("Bouton 3");
groupe.add(bouton3);
pannel.add(bouton3);
f.getContentPane().add(pannel);
f.setVisible(true);
}
}
Les constructeurs sont les suivants :
Constructeur Rôle
JCheckBox(String) précise l'intitulé
JCheckBox(String, boolean) précise l'intitulé et l'état
JCheckBox(Icon) précise une icône comme intitulé
JCheckBox(Icon, boolean) précise une icône comme intitulé et l'état
JCheckBox(String, Icon) précise un texte et une icône comme intitulé
JCheckBox(String, Icon, boolean) précise un texte et une icône comme intitulé et l'état
Un groupe de cases à cocher peut être défini avec la classe ButtonGroup. Dans ce cas, un seul composant du groupe peut être sélectionné. Pour l'utiliser, il faut créer un objet de la classe ButtonGroup et utiliser la méthode add() pour ajouter un composant au groupe.
import javax.swing.*;
public class TestJCheckBox1 {
public static void main(String argv[]) {
JFrame f = new JFrame("ma fenetre");
f.setSize(300,100);
JPanel pannel = new JPanel();
JCheckBox bouton1 = new JCheckBox("Bouton 1");
pannel.add(bouton1);
JCheckBox bouton2 = new JCheckBox("Bouton 2");
pannel.add(bouton2);
JCheckBox bouton3 = new JCheckBox("Bouton 3");
pannel.add(bouton3);
f.getContentPane().add(pannel);
f.setVisible(true);
}
}
Les constructeurs sont les mêmes que ceux de la classe JCheckBox.
import javax.swing.*;
public class TestJRadioButton1 {
public static void main(String argv[]) {
JFrame f = new JFrame("ma fenetre");
f.setSize(300,100);
JPanel pannel = new JPanel();
JRadioButton bouton1 = new JRadioButton("Bouton 1");
pannel.add(bouton1);
JRadioButton bouton2 = new JRadioButton("Bouton 2");
pannel.add(bouton2);
JRadioButton bouton3 = new JRadioButton("Bouton 3");
pannel.add(bouton3);
f.getContentPane().add(pannel);
f.setVisible(true);
}
}
Swing possède plusieurs composants pour permettre la saisie de texte.
La classe abstraite JTextComponent est la classe mère de tous les composants permettant la saisie de texte.
Les données du composant (le modèle dans le motif de conception MVC) sont encapsulées dans un objet qui implémente l'interface Document. Deux classes implémentant cette interface sont fournies en standard : PlainDocument pour du texte simple et StyledDocument pour du texte riche pouvant contenir entre autre plusieurs polices de caractères, des couleurs, des images, ...
La classe JTextComponent possède de nombreuses méthodes dont les principales sont :
Méthode Rôle
void copy() Copier le contenu du texte et le mettre dans le presse papier système
void cut() Couper le contenu du texte et le mettre dans le presse papier système
Document getDocument() Renvoyer l'objet de type Document qui encapsule le texte saisi
String getSelectectedText() Renvoyer le texte sélectionné dans le composant
int getSelectionEnd() Renvoyer la position de la fin de la sélection
int getSelectionStart() Renvoyer la position du début de la sélection
String getText() Renvoyer le texte saisie
String getText(int, int) Renvoyer une portion du texte incluse à partir de la position donnée par le premier paramètre et la longueur donnée dans le second paramètre
bool isEditable() Renvoyer un booléen qui précise si le texte est éditable ou non
void paste() Coller le contenu du presse papier système dans le composant
void select(int,int) Sélectioner une portion du texte dont les positions de début et de fin sont fournies en paramères
void setCaretPosition(int) Déplacer la curseur à la position dans le texte précisé en paramètre
void setEditable(boolean) Permet de préciser si les données du composant sont éditables ou non
void setSelectionEnd(int) Modifier la position de la fin de la sélection
void setSelectionStart(int) Modifier la position du début de la sélection
void setText(String) Modifier le contenu du texte
Toutes ces méthodes sont donc accessibles grâce à l'héritage pour tous les composants de saisie de texte proposés par Swing.
La classe javax.Swing.JTextField est un composant qui permet la saisie d'une seule ligne de texte simple. Son modèle utilise un objet de type PlainDocument.
import javax.swing.*;
public class JTextField1 {
public static void main(String argv[]) {
JFrame f = new JFrame("ma fenetre");
f.setSize(300, 100);
JPanel pannel = new JPanel();
JTextField testField1 = new JTextField ("mon texte");
pannel.add(testField1);
f.getContentPane().add(pannel);
f.setVisible(true);
}
}
La propriété horizontalAligment permet de préciser l'alignement du texte dans le composant en utilisant les valeurs JTextField.LEFT , JTextField.CENTER ou JTextField.RIGHT.
La classe JPasswordField permet la saisie d'un texte dont tous les caractères saisis seront affichés sous la forme d'un caractère particulier ('*' par défaut). Cette classe hérite de la classe JTextField.
import java.awt.Dimension;
import javax.swing.*;
public class JPasswordField1 {
public static void main(String argv[]) {
JFrame f = new JFrame("ma fenetre");
f.setSize(300, 100);
JPanel pannel = new JPanel();
JPasswordField passwordField1 = new JPasswordField ("");
passwordField1.setPreferredSize(new Dimension(100,20 ));
pannel.add(passwordField1);
f.getContentPane().add(pannel);
f.setVisible(true);
}
}
La méthode setEchoChar(char) permet de préciser le caractère qui sera utilisé pour afficher la saisie d'un caractère.
Il ne faut pas utiliser la méthode getText() qui est déclarée deprecated mais la méthode getPassword() pour obtenir la valeur du texte saisi.
import java.awt.Dimension;
import java.awt.event.*;
import javax.swing.*;
public class JPasswordField2 implements ActionListener {
JPasswordField passwordField1 = null;
public static void main(String argv[]) {
JPasswordField2 jpf2 = new JPasswordField2();
jpf2.init();
}
public void init() {
JFrame f = new JFrame("ma fenetre");
f.setSize(300, 100);
JPanel pannel = new JPanel();
passwordField1 = new JPasswordField("");
passwordField1.setPreferredSize(new Dimension(100, 20));
pannel.add(passwordField1);
JButton bouton1 = new JButton("Afficher");
bouton1.addActionListener(this);
pannel.add(bouton1);
f.getContentPane().add(pannel);
f.setVisible(true);
}
public void actionPerformed(ActionEvent e) {
System.out.println("texte saisie = " + String.copyValueOf(passwordField1.getPassword()));
}
}
Les méthodes copy() et cut() sont redéfinies pour empêcher l'envoi du contenu dans le composant et émettre simplement un beep.
Le JDK 1.4 propose la classe JFormattedTextField pour faciliter la création d'un composant de saisie personnalisé. Cette classe hérite de la classe JTextField.
Ce composant permet de saise de texte riche multi-lignes. Ce type de texte peut contenir des informations de mise en pages et de formatage. En standard, Swing propose le support des formats RTF et HTML.
import java.net.URL;
import javax.swing.*;
import javax.swing.event.*;
public class JEditorPane1 {
public static void main(String[] args) {
final JEditorPane editeur;
JPanel pannel = new JPanel();
try {
editeur = new JEditorPane(new URL("http://google.fr"));
editeur.setEditable(false);
editeur.addHyperlinkListener(new HyperlinkListener() {
public void hyperlinkUpdate(HyperlinkEvent e) {
if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
URL url = e.getURL();
if (url == null)
return;
try {
editeur.setPage(e.getURL());
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
});
pannel.add(editeur);
} catch (Exception e1) {
e1.printStackTrace();
}
JFrame f = new JFrame("ma fenetre");
f.setSize(500, 300);
f.getContentPane().add(pannel);
f.setVisible(true);
}
}
c’est une Classe représente une amélioration sensible par rapport AWT's TextArea. Il permet des combinaisons complexes de caractère et de paragraphe attributs, les images intégrées et des composants, ainsi que d'autres fonctionnalités qui vous permettent de construire des éditeurs de texte de style. Malheureusement, alors que JTextPane rend les choses complexes possible, il rend difficile certaines choses simples. Deux exemples sont en train de mettre la police par défaut et couleur.
La classe JTextArea est un composant qui permet la saisie de texte simple en mode multi-lignes. Le modèle utilisé par ce composant est le PlainDocument : il ne peut donc contenir que du texte brut sans éléments multiples de formatage.
JTexteArea propose plusieurs méthodes pour ajouter du texte dans son modèle :
soit fournir le texte en pramètre du constructeur utilisé
soit utiliser la méthode setText() qui permet d'initialiser le texte du composant
soit utiliser la méthode append() qui permet d'ajouter du texte à la fin de celui contenu dans le texte du composant
soit utiliser la méthode insert() permet d'insérer un texte à une position données en caractères dans dans le texte du composant
La méthode replaceRange() permet de remplacer une partie du texte désignée par la position du caractère de début et la position de son caractère de fin par le texte fourni en paramètre.
La propriété rows permet de définir le nombre de ligne affichée par le composant : cette propriété peut donc être modifié lors d'un redimensionnement du composant. La propriété lineCount en lecture seule permet de savoir le nombre de lignes dont le texte est composé. Il ne faut pas confondre ces deux propriétés.
import javax.swing.*;
public class JTextArea1 {
public static void main(String argv[]) {
JFrame f = new JFrame("ma fenetre");
f.setSize(300, 100);
JPanel pannel = new JPanel();
JTextArea textArea1 = new JTextArea ("mon texte");
pannel.add(textArea1);
f.getContentPane().add(pannel);
f.setVisible(true);
}
}
Par défaut, la taille du composant augmente au fur et à mesure de l'augmentation de la taille du texte qu'il contient. Pour éviter cet effet, il faut encapsuler le JTextArea dans un JScrollPane.
import java.awt.Dimension;
import javax.swing.*;
public class JTextArea1 {
public static void main(String argv[]) {
JFrame f = new JFrame("ma fenetre");
f.setSize(300, 100);
JPanel pannel = new JPanel();
JTextArea textArea1 = new JTextArea ("mon texte");
JScrollPane scrollPane = new JScrollPane(textArea1);
scrollPane.setPreferredSize(new Dimension(200,70));
pannel.add(scrollPane);
f.getContentPane().add(pannel);
f.setVisible(true);
}
}
JTable est un composant extrêmement utile mais malheureusement assez complexe. En effet un package complet, nommé javax.swing.table lui est consacré.
Le composant JTable permet d’afficher des tables de données. Un JTable ne contient pas ses données mais les obtient à partir d’un tableau d’objets à 2 dimensions, ou à partir d’un modèle de données.
Exemple de JTable :
La classe JTable implémente l’interface Scrollable (ce qui signifie qu’il peut être placé dans un JScrollPane).
Chaque JTable dispose de trois modèles qui sont :
· TableModel
· TableColumnModel
· ListSelectionModel.
TableModel définit la manière dont sont stockées les données, et gèrées les ajouts et suppressions ainsi que la récupération des données. Il définit aussi les types de données de chaque colonne, et spécifie aussi si une cellule est éditable. Toutes les données de la table sont stockées dans le TableModel (tableau à 2 dimensions ou vecteur de vecteurs).
TableColumnModel gère des instances de TableColumn (c'est-à-dire une colonne de la table). TableColumnModel est responsable de l’affichage des colonnes dans la table. Chaque TableColumn possède un cell renderer, un cell editor, un table header, et un cell renderer pour le table header.
ListSelectionModel définit le mode de sélection (single-interval, multiple-interval). ListSelectionModel est très flexible et permet de personnaliser les sélections de toutes les manières que l’on souhaite.
La méthode la plus simple pour construire une table est de passer un vecteur de vecteurs en paramètres du constructeur.
Le constructeur suivant va être utilisé :
JTable (Vector rowData, Vector columnNames)
Ce constructeur reçoit des vecteurs de vecteurs (rowData pour les lignes, columnNames pour les entêtes).
Pour pouvoir ensuite afficher la table il est préférable d’utiliser l’interface Scrollable implémentée par JTable.
Nous allons nous intéresser ici à un mécanisme particulièrement utile qui est celui de l’utilisation des renderers. En l’occurrence il va s’agir ici de DefaultTableCellRenderer.
Le principe est de s’appuyer sur les renderers par défaut. Pour cela la JTable doit connaître le type de données à afficher, il va s’adresser à l’objet qui encapsule les données, c'est-à-dire le TableModel.
Il y a alors deux cas possible :
· Il n’existe pas de TableModel créé par l’utilisateur. JTable utilise le TableModel créé par défaut.
· S’il existe un TableModel personnalisé, alors la JTable s’adresse à ce dernier.
Une fois que JTable connaît le type de données à afficher, il se réfère à son dictionnaire liant les types et leurs renderers associés.
Ce dictionnaire contient par défaut la liste suivante :
· Boolean (JCheckbox)
· Number (JLabel aligné à droite)
· Date (JLabel formaté avec DateFormat et aligné à droite)
· ImageIcon (JLabel aligné au centre)
· Object (JLabel aligné à gauche affichant une chaîne de caractères)
Il va donc s’agir de redéfinir un TableModel pour notre JTable et de lui inclure la méthode qui renvoie le type d’objet.
Par défaut les cellules d’une JTable sont éditables. Par contre, lorsque l’on utilise un renderer personnalisé, on peut choisir de rendre le tableau non éditable.
Il est souvent possible que l’on cherche à mettre en place une manière précise d’éditer une cellule, par exemple de faire apparaître une JList où l’on doit sélectionner une valeur.
Le fonctionnement des editors est très similaire à celui des renderers. Lorsque l’utilisateur cherche à modifier le contenu d’une cellule (double clic, saisie clavier), l’editor prend le contrôle sur la cellule.
Voici le fonctionnement des Editors :
Comme dans le cas des renderers, on est assez libre dans l’implémentation. On peut choisir d’hériter d’un composant graphique (extends JLabel ….), ou bien d’encapsuler ce composant dans une variable d’instance.
Il est toutefois indispensable d’implémenter l’interface en question (ici CellEditor).
Pour illustrer l’implémentation d’un editor appliqué à notre illustration précédente, on considère que l’utilisateur doit choisir une planète dans une liste déroulante.
Une manière simple de créer un editor est d’utiliser la classe DefaultCellEditor. Celle-ci encapsule le composant graphique sous la forme d’une variable nommée editorComponent. Il est possible d’afficher un JTextField, une JCheckBox ou encore une JComboBox.
DefaultCellEditor dispose de constructeurs permettant d’accepter chacun des composants précités.
Nous obtenons l’illustration suivante :
Une autre manière de créer un editor personnalisé consiste à hériter de AbstractCellEditor, et d’implémenter les fonctions getTableCellEditorComponent() et getCellEditorValue()
En voici un exemple :