L’interface graphique événementielle

Accueil

Définition

Une interface graphique est composée de l’ensemble des éléments
par lesquels l’utilisateur interagit avec le logiciel:

Chacun d’eux est conçu pour déclencher une action bien précise.
L’essentiel n’est pas de les voir tous, avec toutes leurs méthodes,
mais d’en comprendre la philosophie.

La fenêtre

Le fenêtre est l’élément principal de l’application.
Elle en accueille tous les composants.
En Java, il s’agit de l’objet JFrame.
A ce titre, elle se comporte comme un conteneur, dont elle hérite.

En elle-même, elle est déjà un élément d’interface,
susceptible de provoquer certains événements lorsqu’elle est écoutée par un WindowListener

windowOpened Lorsque la fenêtre est ouverte, créée.
windowActivated Lorsque la fenêtre devient active
windowDeactivated Lorsque la fenêtre devient inactive, perd le focus au profit d’une autre fenêtre
windowIconified Lorsque la fenêtre est icônisée
windowDeiconified Lorsque la fenêtre passe de l’état icônisé à l’état de fenêtre normale.
windowClosing Avant la fermeture
Possibilité de refuser la fermeture si elle contient encore un document non sauvé par exemple.
windowClosed Après la fermeture la fermeture

 

Tous ces événements sont automatiquement générés par Eclipse
lorsque vous construirez une sous-classe qui implements WindowListener.

 

Les layouts managers

Une fenêtre peut changer de dimension d’un utilisateur à l’autre.
Positionner les composants sur l’interface peut se révéler fastidieux.
Heureusement, nous avons, pour cela, des auxiliaires qui vont nous aider à les positionner automatiquement.

Java propose différents Layout Managers

Le FlowLayout

C’est le plus élémentaire.
this.setLayout(new FlowLayout(FlowLayout.RIGHT));

Tous les composants sont placés à la suite les uns des autres,
comme les caractères d’un traitement de texte.
Lorsque la largeur de la fenêtre (ou de tout autre conteneur) est atteinte et dépassée,
le composant suivant passe à la ligne suivante.

Trois variantes sont possibles :

Doc Oracle

Le BorderLayout

Il divise le conteneur en cinq zones

  1. Le haut : BorderLayout.NORTH
  2. Le bas : BorderLayout.SOUTH
  3. A gauche : BorderLayout.WEST
  4. A droite : BorderLayout.EAST
  5. Au centre : BorderLayout.CENTER

Ce layout manager ne permet donc que d’accueillir cinq composants.
La zone nord accueille, en général, une barre de menus déroulants.
Les zones périphériques ont une largeur ou hauteur minimales.

La zone centre occupe tout le reste de l’espace disponible.
Lorsque la fenêtre change de dimensions,
c’est la zone centrale qui change de taille en conséquence.

Doc Oracle

Le GridLayout

Il découpe le conteneur en zones selon un quadrillage en lignes et en colonnes, un peu comme une feuille Excel.

this.setLayout(new GridLayout(3, 2));
Les deux paramètres indiquent respectivement le nombre de lignes et de colonnes souhaités.
Attention, les composants sont disposés D’ABORD de gauche à droite, PUIS de haut en bas.
Chaque cellule accueille un composant.

Un autre paramétrage du constructeur est possible,
pour créer un espace (gap) entre deux composants contigus.
this.setLayout(new GridLayout(3, 2, 5, 8));
Les composants seront séparés d’un intervalle horizontal de 5 pixels, et vertical de 8 pixels.

Doc Oracle

D’autres layout managers existent encore. Ceux énumérés ci-dessus sont seulement les trois principaux.
Le présent syllabus est juste une synthèse de ce que nous avons vu au cours.
Il n’a pas la prétention de remplacer une documentation complète sur le sujet.

Vous pouvez très facilement en apprendre plus en tapant simplement Java Layout Manager dans Google, et en allant consulter les Javadocs online.

Les composants

Ici aussi, les composants en Java sont très nombreux.
La liste en tête de cette page reprend les principaux.

Une remarque s’impose: le JPanel, qui peut accueillir des composants, est un composant comme un autre.
Voilà comment construire récursivement une interface graphique en Java.

Chaque JPanel (qui est un héritier du Container) peut contenir et être contenu dans d’autres.
C’est en principe comme ça que fonctionne le BorderLayout, qui ne peut accueillir que cinq composants.
Il n’accueillera pas cinq composants atomiques (boutons, cases à cocher), mais des JPanels, qui, à leur tour,
contiendront des composants disposés selon un layout au choix du développeur.

Un BorderLayout peut donc, en définitive, accueillir bien plus de cinq composants atomiques.

Les événements

Lorsqu’un composant est actionné par l’utilisateur, il doit déclencher une action.
Pour cela, il faut associer un écouteur d’événements au composant.

Cette association n’est pas obligatoire.
Par exemple, on pourra consulter une case à cocher comme une simple variable:

if (maCase.isSelected())
{
 System.out.println("Cochée");
}
else
{
 System.out.println("Non cochée");
}

Si, par contre, on souhaite que le composant déclenche un événement, il faudra lui associer un écouteur :
maCase.addActionListener(monGestionnaire);
Le raisonnement intellectuel est le suivant :

  1. Définir un composant (case, bouton, …)
  2. Définir une classe interne écouteuse d’événements
  3. Instancier un objet de cette classe
  4. Associer l’objet écouteur au composant écouté
  5. Créer, dans la classe interne, un if (ou un else if) à l’écoute du composant
Dans les déclarations de variables
private JCheckBox maCase = new JCheckBox("Choix"); Création d’une case à cocher
private Gestionnaire monGestionnaire = new Gestionnaire(); Création d’une variable écouteuse d’événements
Dans le constructeur de la JFrame
this.setLayout(new BorderLayout()); On donne un layout à la JFrame, peu importe lequel.
this.add(maCase, BorderLayout.SOUTH); On positionne la case dans son conteneur (La JFrame)
maCase.addActionListener(monGestionnaire); La case reçoit un gestionnaire d’événements
Plus bas, dans la classe conteneur (ici héritée de JFrame),
après toutes les méthodes de classes, et au même niveau d’indentation, on définit une sous-classe privée interne,
arbitrairement nommée Gestionnaire :
private class Gestionnaire implements ActionListener
{
 @Override
 public void actionPerformed(ActionEvent arg0)
 {
  if (arg0.getSource() == monBouton01)
  {
   System.out.println("Bouton01");
  }
  else if (arg0.getSource() == monBouton02)
  {
   System.out.println("Bouton02");
  }
  else if (arg0.getSource() == maCase)
  {
   if (maCase.isSelected())
   {
    System.out.println("Cochée");
   }
   else
   {
    System.out.println("Vide");
   }
  }

  else if (arg0.getSource() == monAutreComposant)
  {
   …
  }
}

La classe écouteuse doit implémenter l’interface ActionListener
Ce qui l’oblige à surcharger la méthode abstraite ActionPerformed, qui reçoit en paramètre un événement (arg0).
Eclipse vous le signalera d’un ondulé rouge Add unimplemented methods

En effectuant un test sur arg0, on peut déterminer quel est le composant qui est à la source de l’événement et y répondre par le code adéquat.

Ainsi, la console affichera Cochée ou Vide à l’instant précis où l’utilisateur cochera ou dé-cochera la case.

C’est la base de la programmation événementielle.

Voici le code source créé lors du cours du 21 janvier 2013 consacré aux interfaces graphiques

La classe principale ne fait que créer une fenêtre Fen01
La simple création de Fen01 enclenche son constructeur.
Source
La fenêtre Fen01 définit tous ses composants dans son constructeur.
Elle contient une classe interne écouteuse d’événements.
Source
Parmi les composants de Fen01, un JPanel dessine un cercle de couleur selon trois composantes rouge, verte et bleue Source
Le ControlPanel contrôle le ColorPanel en lui passant des ordres reçus de ses glissières (JSlider)
Le ControlPanel contient un écouteur d’événements dédié aux glissières.
Source