Les composants graphiques avec Swing.
Jusqu'à présent nous utilisions Java en mode console: la communication avec l'utilisateur se réduisant à des entrées/sorties en mode caractère et de manière séquentielle. La bibliothèque Swing permet de développer des applications graphiques de type événementielle.
Nous allons présenter les principaux objets disponibles et la logique de ces applications.
La fenêtre.
Pour créer une fenêtre on peut utiliser la classe JFrame. Cette classe qui possède un constructeur par défaut contient des méthodes qui définissent les caractéristiques de la fenêtre.
import javax.swing.*;
public class TestFen
{
public static void main(String[] args)
{
JFrame fen = new JFrame();
fen.setSize(300,150);
// largeur, hauteur
fen.setTitle("Test de fenètre");
fen.setVisible(true);
}
}
Ce qui produira:
Par défaut la fenêtre générée possède les caractéristiques classiques: réduction, fermeture, redimentionnement...
Bien sûr, nous pouvons instancier plusieurs JFrame.
Remarques:
La fermeture de la fenêtre n'arrête pas le programme, pour cela il faut fermer l'application console.
On peut utiliser la méthode setBounds pour positionner et dimensionner en même temps:
fen.setBounds(100,200,300,150); //le coin haut gauche est aux coordonnées 100, 200 et les dimensions sont 300 *150
Ajouter
un composant dans la fenètre : un bouton
Il faudra installer un objet Jbutton qui possède un constructeur prenant comme argument une chaîne qui s’affichera dans le bouton :
Regardons le code :
import
javax.swing.*;
class
fen extends JFrame
{
fen()
{
setTitle("mon premier bouton");
setSize(300,200);
JButton monBouton = new JButton("test");
getContentPane().add(monBouton);
}
public
static void main(String[] args)
{
fen mafen = new fen();
mafen.setVisible(true);
}
}
La fonction d’accès getContentPane() :
Une fenêtre en Java est une superposition de plusieurs éléments dont une racine, un contenu et une vitre ; c’est dans le contenu de la fenêtre que nous voulons ajouter le bouton, la méthode getContentPane() retourne une référence de ce contenu. A noter que le type retourné est un Container ; ainsi nous aurions pû écrire :
Container c = getContentPane() ;
c.add(monBouton) ;
Si nous lançons l’application :
Le bouton est bien ajouté – il est donc visible par défaut – mais il occupe toute la fenêtre !
Gestion de la mise en forme.
Ceci relève de la responsabilité de classes spécifiques.
C’est le gestionnaire de mise en forme par défaut qui est utilisé –BorderLayout-, puisque aucun n’est déclaré, et ce gestionnaire place le composant sur toute la feuille.
Nous allons utiliser un autre gestionnaire de la classe FlowLayout, qui dispose les composants en flots en commençant par une première ligne.
Pour associer au « contenu » de la fenètre un autre gestionnaire de mise en forme, il faut en créer un de la classe FlowLayout et utiliser la méthode setLayout du « contenu »
…
JButton
monBouton = new JButton("test");
FlowLayout fl = new FlowLayout();
getContentPane().setLayout(fl);
getContentPane().add(monBouton);
...
Il faut importer java.awt.* pour utiliser ce gestionnaire.
Gérer les événements.
Plusieurs techniques peuvent être utilisées, mais dans tous les cas cela nécessite l’utilisation de classes ou d’interfaces qui « écoutent » le composant.
Les deux acteurs principaux sont
- La source de l'événement
- L'écouteur - ou les écouteurs - de l'événement qui va réagir, en général il s'agit du conteneur de la source.
Java propose un mécanisme de relation entre ces deux acteurs basé sur un modèle générique ( pattern Observer ). Sont présentés ici les étapes à suivre
- La source doit inscrire - abonner - les écouteurs dans sa liste d'écouteurs ( cf b)
- Chaque écouteur doit savoir réagir à l'événement ( cf a )
- Lorsque la source est sujette d'un événement elle en informe - notifie - tous les écouteurs en leur passant un objet de type événement ( cf a )
a) Les écouteurs.
Nous allons utiliser une interface ActionListener – Ecouteur d’actions – qui ne possède qu’une seule méthode actionPerformed, qu’il s’agira pour la fenêtre contenant le bouton d’implémenter.
public void
actionPerformed(ActionEvent evt)
{
System.out.println("action");
}
b) La source
Par ailleurs, la méthode addActionListener, présente dans les objets susceptibles d’être l’objet « d’actions » va permettre au bouton d’inscrire l’écouteur.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class fen extends JFrame implements ActionListener
{
fen()
{
setTitle("mon premier bouton");
setSize(300,200);
JButton monBouton = new JButton("test");
FlowLayout fl = new FlowLayout();
getContentPane().setLayout(fl);
getContentPane().add(monBouton);
monBouton.addActionListener(this);
}
public
void actionPerformed(ActionEvent evt)
{
System.out.println("action");
}
public
static void main(String[] args)
{
fen mafen = new fen();
mafen.setVisible(true);
}
}
Remarque :
Il faut noter que actionPerformed correspond à une quelconque « action » sur le bouton, click mais aussi barre d’espacement.
Cas de plusieurs boutons.
Si nous créons plusieurs boutons, qui s’ajoutent à l’écouteur :
JButton
monBouton1 = new JButton("Bouton 1");
JButton monBouton2 = new JButton("Bouton 2");
FlowLayout fl = new FlowLayout();
getContentPane().setLayout(fl);
getContentPane().add(monBouton1);
getContentPane().add(monBouton2);
monBouton1.addActionListener(this);
monBouton2.addActionListener(this);
Une action sur un quelconque bouton génèrera le même événement « action »
public
void actionPerformed(ActionEvent evt)
{
if(evt.getSource()==monBouton1)
System.out.println("action du bouton 1");
if(evt.getSource()==monBouton2)
System.out.println("action du bouton 2");
}
Remarque : pour ce deuxième exemple nous devons déclarer les Jbutton comme attributs de la classe.
La méthode getActionCommand.
la méthode getSource() d'un objet ActionEvent retourne la référence sur l'objet source de l'événement, la méthode getActionCommand retourne une chaîne de caractères - chaîne de commande -; par défaut la chaîne de commande pour un bouton est son étiquette. Dans l'exemple précédent nous pouvions écrire:
public
void actionPerformed(ActionEvent evt)
{
String s = evt.getActionCommand();
if( s.equals("Bouton 1"))
System.out.println("action du bouton 1");
if( s.equals
("Bouton 2")
System.out.println("action du bouton 2");
}
Les champs de texte.
La classe JTextField permet d'instancier des zones de saisie simple.
Plusieurs constructeurs sont disponibles dont:
- Un constructeur à un argument de type entier qui fixe la largeur en caractères de la zone.
- Un constructeur à deux arguments: texte par défaut et largeur.
Une méthode getText() retourne le texte contenu dans le composant.
Une méthode setText( String t) modifie le contenu.
Une méthode setEditable( boolean b) détermine si l'utilisateur peut modifier le contenu.
Application. Modifions le programme précédent afin de faire apparaître les messages dans la zone de texte.
...
monTexte = new JTextField(20);
Container c = getContentPane();
FlowLayout f = new FlowLayout();
c.setLayout(f);
c.add(monBouton);
c.add(monBouton2);
c.add(monTexte);
...
public void actionPerformed(ActionEvent evt)
{
if(evt.getSource()==monBouton)
monTexte.setText("Action 1");
if(evt.getSource()==monBouton2)
monTexte.setText("Action 2");
}
Les
cases à cocher.
Un case à cocher supporte deux états, son constructeur impose un libellé:
JCheckBox case1 = new JCheckBox("Case 1");
On ajoute ensuite la case à son conteneur:
Container c = getContentPane();
c.add( case1);
Au moment de la construction on peut imposer que la case soit cochée:
JCheckBox case1 = new JCheckBox("Case 1", true);
La méthode isSelected() retourne un booleen sur l'état de la case à cocher.
La méthode setSelected(true) coche la case.
Une modification de la case génère un événement de type Action, donc un écouteur pourra implémenter l'interface ActionListener en définissant la méthode actionPerformed.
Les
boutons radio.
C'est objet binaire comme une case à cocher mais il doit être utilisé dans un groupe de boutons, car seul un bouton peut être sélectionné en même temps.
JRadioButton rb1 = new JRadioButton("Bouton 1");
JRadioButton rb2 = new JRadioButton("Bouton 2", true); // sélection par défaut
Ensuite, il faut créer un groupe et associer chaque bouton à ce groupe:
ButtonGroup gr = new ButtonGroup();
gr.add(rb1);
gr.add(rb2);
Mais le groupe de bouton radio n'est pas un composant, et ce sont bien les boutons qu'il faudra insérer dans un conteneur.
Les méthodes isSelected() et setSelected(true) sont les accesseurs et modificateurs de l'état du bouton.
Comme les cases à côcher les boutons radio génèrent des événements Action.
Les
étiquettes.
Un étiquette est une zone de texte non modifiable, sur une ligne:
JLabel texte = new JLabel("un texte");
la méthode setText("texte") permet de modifier le contenu de l'étiquette.