L'objectif de ce TP est de comprendre comment fonctionnent les interfaces graphiques en java.
Il comporte deux parties:
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.
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!
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!
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); }
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.
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.
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.
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); }
Il existe d'autres moyens de lier une méthode avec un ActionListener et un JButton.
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:
Les principaux inconvénients:
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:
Avantage ou inconvénient:
Les principaux inconvénients:
Voici quelques pistes pour vous permettre de faire évoluer votre calculatrice: