Outils pour utilisateurs

Outils du site


java:mvc

Introduction aux interfaces graphiques

L'objectif de ce TP est de comprendre comment fonctionnent les interfaces graphiques en java.

Il comporte deux parties:

  1. Introduction aux composants swing et au positionnement;
  2. La programmation évènementielle et les écouteurs.

Les composants graphiques en java

Il existe plusieurs API en java permettant d'utiliser des composants graphiques. Nous allons en utiliser une en particulier: l'API swing.

Cette API est décrite dans la javadoc de java; son package est javax.swing.

Les composants de cette api ont donc comme référence javax.swing.NonDuComposant. La plupart commencent par la lettre J: JFrame (fenêtre), JButton (bouton), JTextField (champ texte), etc.

Création d'une fenêtre

Voici comment créer une fenêtre (JFrame)

import javax.swing.JFrame;//utilisation du composant JFrame du package javax.swing
 
/**
 * Cette classe nous servira de test pour les composants graphiques
 */
public class TestGraphique
{
	/**
	 *	Constructeur: fabrique une fenêtre
	 */
	public TestGraphique()
	{
		JFrame fenetre = new JFrame("Ma première fenêtre");
		fenetre.setVisible(true);//pour afficher la fenêtre
	}
 
	public static void main(String [] arguments)
	{
		new TestGraphique();
	}
}

Compilez et exécutez le code. Où se trouve la fenêtre?

Comment quitter le programme? (Rappel: ctrl + C permet d'interrompre un programme java dans la console).

Pour remédier à ce problème, ajoutez l'instruction suivante:

	fenetre.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

Conclusion: nous savons faire une fenêtre, mais elle est très (trop) simple pour l'instant!

Créer une fenêtre personnalisée

Java nous donne une version basique de fenêtre, mais cette fenêtre ne nous permet pas de faire grand chose.

En fait, nous voudrions faire une fenêtre personnalisée, avec des boutons, des zones de texte, etc.

JFrame est intéressant car il nous offre un cadre (JContainer). A nous maintenant d'y ajouter ce que l'on veut!

1ère technique: créer un cadre personnalisé

	public TestGraphique()
	{
		JFrame fenetre = new JFrame("Ma première fenêtre");
		fenetre.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		JPanel cadre = new JPanel(); //cadre personnalisé pour la fenêtre
 
		//création des composants à incorporer:
		JLabel etiquette = new JLabel("Entrez une addition");
		JTextField champSaisie = new JTextField(10);
		JButton bouton = new JButton("Calculer");
 
		//ajout des composants au cadre (panneau)
		cadre.add(etiquette);
		cadre.add(champSaisie);
		cadre.add(bouton);
 
		//changement du cadre de la fenêtre avec notre cadre personnalisé
		fenetre.setContentPane(cadre);
		fenetre.setVisible(true);
	}

2ème technique: l'héritage

Il est aussi possible d'utiliser l'héritage pour fabriquer une fenêtre personnalisée.

Faites hériter la classe TestGraphique de JFrame et adaptez le code.

Pour accéder directement au cadre, vous pouvez utilisez getContentPane() de la classe JFrame.

Positionner les composants

Pour l'instant, nos composants sont ajoutés sur la même ligne les uns à la suite des autres.

Nous allons changer ce comportement du cadre en lui donnant un nouveau type de gestionnaire de positionnement (ou gestionnaire de répartition).

Il existe plusieurs types de gestionnaires de positionnement (Layout): BorderLayout, GridLayout, GridBagLayout, FlowLayout, etc.

Nous allons utiliser un des plus simples, le BorderLayout du package java.awt.

Ce composant permet d'indiquer où placer un composant avec 5 contraintes: au nord, au sud, à l'est, à l'ouest, ou au centre.

On ne peut placer qu'un seul composant sur une position. Profitons-en pour donner une taille raisonnable à notre fenêtre.

		//utilisation d'un nouveau Layout pour le cadre
		cadre.setLayout(new BorderLayout());
		//ajout des composants au cadre (panneau)
		cadre.add(etiquette,BorderLayout.WEST);
		cadre.add(champSaisie, BorderLayout.CENTER);
		cadre.add(bouton, BorderLayout.SOUTH);
 
		fenetre.setSize(300,100);//change la taille de la fenêtre

Et voilà pour la base! Complétez votre interface graphique en ajoutant d'autres composants, en changeant les couleurs, en utilisant un autre gestionnaire de positionnement, etc.

2ème partie: les évènements

Les bases

Nous savons maintenant faire une interface graphique de base en java. Mais nous n'avons pas encore de possibilités d'interaction avec elle.

En java, une interface graphique génère une quantité d'évènements: déplacement de la fenêtre, clic sur un composant, déplacement de la souris, frappe au clavier, etc… La plupart du temps, seul un tout petit nombre de ces évènements nous intéresse.

Dans notre cas, nous allons commencer par gérer l'évènement produit lorsqu'on clique ou qu'on active le bouton.

Ce type d'évènement est un ActionEvent. Pour pouvoir l'intercepter, nous allons utiliser un composant spécifique, un ActionListener.

ActionListener est une interface. Il va donc falloir l'implémenter pour pouvoir écrire notre code.

  1. Commençons par faire implémenter ActionListener par TestGraphique. Quelle méthode doit-on redéfinir?
  2. Indiquons maintenant au bouton quel(s) est (sont) son (ses) écouteur(s):
	bouton.addActionListener(this);

Que se passe-t-il maintenant lorsqu'on clique sur le bouton?

Que se passe-t-il si on écrit deux fois bouton.addActionListener(this);?

Utilisez maintenant la méthode calcule() suivante pour réaliser le calcul. Pourquoi est-elle private?

Que devez-vous modifier pour pouvoir l'utiliser?

	/** Mais que fait donc cette méthode? */
	private void calcule()
	{
		String resultat = "";
		String saisie = champSaisie.getText();
		String [] operandes = saisie.split("[+]");//+doit être échappé car il est utilisé dans les expressions régulières
		if(operandes.length == 2)
		{
			int i = 0;
			int j = 0;
			try
			{
				i = Integer.parseInt(operandes[0]);
				j = Integer.parseInt(operandes[1]);
				resultat = saisie + "=" + (i+j);
			}
			catch(NumberFormatException nfe)
			{
				resultat = "Erreur de saisie";
			}
		}
		else
		{
			resultat = "Erreur: addition simple uniquement";
		}
		champSaisie.setText(resultat);
	}

Autres méthodes

Il existe d'autres moyens de lier une méthode avec un ActionListener et un JButton.

Classe externe implémentant ActionListener

Rien n'empêche d'utiliser un ActionListener défini dans une autre classe!

Ajouter une instance de MonActionListener à votre bouton. Que se passe-t-il?

import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
/**
 * Cette classe implémente un ActionListener qui ferme l'application en cours
 */
public class MonActionListener implements ActionListener
{
	//constructeur 
	public MonActionListener(){}
 
	public void actionPerformed(ActionEvent ae)
	{
		System.out.println("Au revoir");
		System.exit(0);
	}
}

Les principaux avantages:

  • éviter de trop surcharger la classe fenêtre
  • séparer la partie graphique de la partie fonctionnelle (principe du M-V-C)
  • pouvoir utiliser des techniques d'objet sur les écouteurs (héritage, redéfinitions, etc.)
  • regrouper les traitements évènementiels

Les principaux inconvénients:

  • si l'évènement concerne uniquement la partie graphique, il est plus simple de le gérer dans la partie graphique!
  • la conception est un peu plus complexe…
  • … et la mise en œuvre un peu plus technique, même si elle permet souvent de réaliser un code “propre” et modulaire

Implémentation à la volée (à la JDev)

Il est aussi possible de réaliser les opérations d'affectation (addActionListener), d'implémentation (définition de actionPerformed) et d'appel à méthode extérieure(calcule()) en une seule instruction!

Le principe est le suivant: créer un ActionListener et lui indiquer comment redéfinir la méthode actionPerformed AU MOMENT de sa création.

C'est la technique utilisée par défaut par JDev. Ca ne veut pas dire que vous êtes obligés de l'utiliser!

bouton.addActionListener(new ActionListener()
			{
				public void actionPerformed(ActionEvent ae)
				{
					System.out.println("Je t'ai reconnu JDev");
					calcule();
				}
			});

Les principaux avantages:

  • tout est écrit au même endroit au même moment

Avantage ou inconvénient:

  • l'interface graphique est directement liée à la méthode appelée (calcule())

Les principaux inconvénients:

  • il n'est pas facile de modifier l'ActionListener
  • 1 composant = 1 ActionListener, pas de regroupement
  • le code n'est pas facile à comprendre, et souvent les programmeurs ne comprennent pas ce qu'ils font… ou ont l'impression que ça fonctionne par “magie”!

Pour finir...

Voici quelques pistes pour vous permettre de faire évoluer votre calculatrice:

  1. ajoutez un bouton “effacer” qui vide le champ de saisie; vous pourrez avoir besoin de la méthode getSource() de ActionEvent…
  2. utilisez un GridLayout ou un GridBagLayout à la place du BorderLayout (voir tutoriels);
  3. utilisez un WindowsListener qui affiche “au revoir” lorsque vous fermez la fenêtre;
  4. utiliser un KeyListener pour contrôler la saisie….
  5. etc!

Tutoriels et liens

java/mvc.txt · Dernière modification : 2012/09/26 14:26 de bruno