7- Manipulation de l'interface graphique


7.1 Premières Notions

7.2 Création et manipualtion de Fenêtre : JFrame

7.3 Manipulation de component

7.4 Manipulation de Container - Les LayoutManager

7.5 Gestion des évenements

7.6 Quelques exemples

7.7 Une classe Graphique


7.1 Premières notions

En informatique, les débats sont nombreux sur les formes que doivent prendre les modèles objets relatifs à la programmation graphique : les notions qui apparaissent dans le modèle objet de java ou la manière de les manipuler restent des choix de programmation particuliers qui font l'objet de débats théoriques. Le cours se contente de signaler ces débats sans les développer.

Comme le cours sur le modèle objet de java l'indique, deux bibliothèques constituent l'API graphique, c'est à dire les ressources pour la programmation graphiques : java.awt, javax.swing. Historiquement, java.awt est plus ancien.

Les notions principales à distinguer :

De manière générale, on va s'intéresser à des composants de la bibliothèque javax.swing qui sont à la fois des Container et des Component : des JPanel, sur lesquels on va pouvoir dessiner ou au sein desquelles on va organiser d'autres composants, des JFrame : la fenêtre de base que l'on utilise, des JButton etc. Ces composants sont de plus hauts niveaux que les composants contenus dans la librairie java.awt; comme Windows, Frame etc.... Les composants de javax.swing sont plus aisés d'accès et d'usage. Dans Awt, on a une série de classes de base, dont la plupart ne sont pas évoquées (cf la remarque précédente). Parmi celles à retenir et qui vont être manipulés, on peut notamment retenir Color et Dimension :

La classe Color :

La classe Dimension qui est un objet qui représente un Dimensionnement : une largeur et une hauteur (en pixels ou picture elements). Pour tout composant (JFrame, JPanel, etc) il est possible de récupérer sa dimension :

JFrame fen=new JFrame();
Dimension d=fen.getSize();


La Dimension peut ensuite être manipulée :


7.2 Création et manipulation de fenêtre : JFrame

Le code suivant suffit à la création et l'affichage d'une fenêtre, les commentaires expliquent ce à quoi correspond chaque instruction :

import javax.swing.JFrame;

public class TestJFrame{	

public static void main(String[] args)
	{
	/*Création de la fenetre*/
	JFrame fen=new JFrame();
	/*Reglage de la taille de la fenêtre*/
	fen.setSize(300,300);
	/*Positionnement de la fenêtre*/
	fen.setLocation(10,10);
	/*Cette instruction permet de faire que le programme s'arrête avec un clic sur la croix en haut à droite*/
	/*Il existe d'autres méthodes pour réaliser cela*/
	/*Tester l'exécution de la fenêtre sans cette instruction*/
	fen.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	/*Jusque là la fenêtre était créée mais pas affichée : setVisible(true) appelle son affichage*/
	fen.setVisible(true);
	}
}


On note qu'alors que l'ensemble du code est exécuté, le programme ne se termine pas. Auparavant : des instructions de code étaient exécutées de manière linéaire. En programmation graphique, les actions de l'utilisateur vont déclencher tel ou tel code : le code associé au clic souris, le code associé à l'item "ouvrir" du menu "Fichier", le code associé au passage de la souris dans la fenêtre etc...

Tous les éléments qui apparaissent à l'exécution du code précédent sont paramètrables : le fait que le logo de java soit affiché, le titre etc... par exemple en utilisant fen.setTitle("Titre de la fenetre");, on peut spécifier un titre qui apparaîtra.

Une JFrame peut contenir directement des Component en temps que Container, mais une bonne démarché de programmation consiste à utiliser le container unique crée en même temps que la JFrame et qui lui est associé. Pour le manipuler :

fen.getContentPane();
On peut ensuite ajouter des élements au sein du container de la fenêtre :

import javax.swing.*;
import java.awt.*;

public class TestJFrame{	

public static void main(String[] args)
	{
	/*Création de la fenetre*/
	JFrame fen=new JFrame();
	/*Reglage de la taille de la fenêtre*/
	fen.setSize(300,300);
	/*Positionnement de la fenêtre*/
	fen.setLocation(10,10);
	/*Cette instruction permet de faire que le programme s'arrête avec un clic sur la croix en haut à droite*/
	/*Il existe d'autres méthodes pour réaliser cela*/
	/*Tester l'exécution de la fenêtre sans cette instruction*/
	fen.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	fen.getContentPane().add(new JButton("Test"));
	/*Jusque là la fenêtre était créée mais pas affichée : setVisible(true) appelle son affichage*/
	fen.setVisible(true);		
	}
}

7.3 Manipulation de component

Pour un composant n'en contenant pas d'autres, lorsque le système veut l'afficher, il utilise la fonction paint(Graphics) de ce composant en fournissant l'objet Graphics qui correspond au contexte graphique pour l'affichage : vous n'avez donc pas à vous préoccuper de cet objet. Lorsque le système affiche un composant composé de plusieurs composants, il utilise les fonctions paint des sous-composants ou des sous sous-composants si les sous-composants sont eux-mêmes composés de composants.

Pour les composants qui sont donnés tels quels (les boutons, les menus, JFrame etc...), la méthode paint(Graphics) est déjà définie et détermine ce qui apparaît à l'affichage du Component. Elle est appellée par la JVM à chaque fois qu'il est nécessaire de réafficher (lorsque une fenêtre a été ouverte par dessus par exemple). Pour certains objets, il est possible de la surdéfinir et de donner soit même une forme au composant. Donc pour définir un composant affichable : on fait une classe qui hérite de JPanel et on surdéfinit la méthode paint(Graphics) en décrivant l'affichage.

Dans ce qui suit, on explique comment définir ce qui est à dessiner sur un component. Notons d'abord le système de coordonnées utilisés. Le système de coordonnées est tel que le point en haut à gauche est l'orgine, soit un Panel de taille 100*100 : alors le point en haut à gauche est (0,0), le point en bas à gauche est (0,100) et le point en bas à droite : (100,0). Les valeurs entières sont traduites en pixels (picture elements).





Soit un premier exemple d'affichage :
ExempleAffichageComp.java. Cet exemple illustre l'affichage de chaines de caractères ou de lignes. De manière générale, Graphics propose un certains nombre de méthodes : Pour avoir la définition précise et exhaustive de ces élements, on peut se réferer à la documentation standard de l'API java (entrer Graphics+java+sun dans Google). ou utiliser le lien direct : classe Graphics.





Quelques exemples :

Un premier exemple très simple d'affichage de ligne : LigneBanale.java

Un exemple d'affichage d'un dégradé de couleur autour d'un point central : on passe en paramètre un nombre de petits ovales à afficher : CercleDegrade1.java. Il est conseillé de passer du temps sur ce type de code pour bien comprendre toutes les instructions.

Lors des modifications de l'interface graphique relative à un composant (passage d'une fenêtre sur une autre fenêtre par exemple), le système d'exploitation gère l'affichage en utilisant les fonction paint(Graphics). Donc ces évenements ne sont pas à gérer. En revanche, l'évolution du code peut nécessiter un réaffichage : dans ce cas, on peut forcer l'interface à redessiner un comportement,ceci se fait avec l'appel de repaint() de Component. Voir la partie sur les évenements.


7.4 Manipulation de Container - Les LayoutManager

Un Container est composé de un ou plusieurs composants. Cependant, il faut gérer l'organisation de ces composants : lequel placer en haut à gauche ? Lequel mettre en bas à droite ? etc... Un attribut du Container est de type LayoutManager, il est possible de fixer le LayoutManager en diposant d'un objet lay de type LayoutManager : setLayoutManager(lay);

On donne pour l'instant un unique exemple qui montre différents modes d'organisation :
TestLayout.java


7.5 Gestion des évenements

Pour un composant, on peut lui associer des listeners/écouteurs qui contiennent un code qui sera associé à certains évenements.

Prenons le cas de l'interface MouseListener : un objet qui l'implémente réagit aux évenements de la souris. Si on veut rendre un composant réactif aux évenements de la souris : on fait du composant un mouseListener OU on lui associe un objet qui est un MouseListener et on ajoute cet objet à la liste des listeners associés au composant.

/*SOL1 comp est d'une classe qui implémente MouseListener, on associe le listener this à la liste des listeners*/
comp.addMouseListener(this);
/*Dans ce cas comp s'écoute lui même*/


Plus clair en premier approche :

/*SOL2, on a un objet de type MouseListener ml et on l'associe au composant : */
comp.addMouseListener(ml);
/*Dans ce cas ml s'écoute les évenements de la souris sur comp*/


Les méthodes à définir en implémentant l'interface MouseListener (en effet, MouseListener est une interface, on est donc obligé de coder chacune des méthodes suivantes, il est bien sûr possible de faire un code vide :

A partir de là, on développe les deux solutions évoquées plus haut dans un cas simple :

JFrameML.java, ici l'objet est son propre écouteur : voir sur le command prompt se qui se passe quand on interagit avec la souris sur la fenêtre.

JFrameEcoutee.java, ici on définit un écouteur avec une nouvelle classe. On ne réagit qu'aux clics ici (on pourrait réagir à tous les évenements comme avec JFrameML).

Pour ce dernier exemple, on définit une classe Ecouteur qui implémente MouseListener, notez qu'il s'agit d'une classe interne définie à l'intérieur d'une autre classe. En fait il existe d'autres possibilités que le simple "un fichier-une classe". Ces possibilités ont été éliminées pour simplifier le discours. Essayer de définir l'écouteur avec une classe externe. Cela marchera très bien.

Notez également que l'on dispose d'attributs de l'objet MouseEvent : l'endroit ou se produit l'évenement dans le composant : de sorte qu'il sera possible d'interagir avec les composants ensuite. D'où viennent les objets MouseEvent ? Le système d'exploitation "passe" l'évenement à la JVM voyant que la souris agit sur une fenêtre qui dépend de la JVM. La JVM traduit cet évenement et crée un objet MouseEvent qu'elle passe au composant concerné.





La gestion d'un autre évenement possible : KeyEvent :

L'exemple d'une fenêtre qui écoute les évenements claviers : TestKeyEvent.java : voir le command Prompt lorsqu'on utilise les touches du clavier alors que la fenêtre est active.

Un exemple d'éditeur de texte (très très limité) : TestKeyEvent2.java

Il existe bien sûr beaucoup d'autres écouteurs d'évenements, mais ils fonctionnent sur le même principe. Pour les component, il existe une interface ComponentListener qui permet de définir un comportement dans le cas de redimensionnement du Component, dans le cas où il est déplacé etc...

Pour les boutons (par exemple JButton), on leur associe un écouteur d'évenement ActionListener qui va définir leur comportement lorsqu'ils sont cliqués (bien sur il est toujours possible de rajouter un MouseListener sur un Bouton, c'est le cas de l'affichage des fenêtre d'aide lorsque la souris passe sur le bouton).


7.6 Quelques exemples


7.7 Graphiques

L'ensemble de ces classes est nécessaire pour l'affichage de graphique :
Un classe pour tester l'affichage de graphique :