Interface graphique

Pour commencer

Packages

  • java.awt: première bibliothèque. Fournit des interfaces et des composants limités en code natif.

  • javax.swing: seconde bibliothèque. Ne remplace pas java.awt, mais la complète avec des composants originaux et/ou performants, écrits en Java.

  • On va utiliser javax.swing en priorité (composants commençant par J), mais aussi java.awt (layout managers, événements).

Hello World

import javax.swing.*;       
public class HelloWorldSwing implements Runnable {
    @Override 
    public void run() {
        //Create the window
        JFrame f = new JFrame("HelloWorldSwing");
	//Set the behavior for when the window is closed
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //Add a label
        f.getContentPane().add(new JLabel("Hello world!"));
        //Set the window size from its components size 
        f.pack();
        //By default, the window is not visible; make it visible
        f.setVisible(true);
    }
    public static void main(String[] args) {
	//Run the application at the correct time in the event queue
        SwingUtilities.invokeLater( new HelloWorldSwing() );  
    }
}

Event-Dispatching Thread

  • Au lancement d’une application graphique, en plus du thread principal, est lancé un second thread appelé Event-Dispatching Thread (EDT).

  • Une application graphique est réactive aux évenements (clic sur un bouton par exemple). Or les réactions (affichage d’un commentaire par exemple) sont placées dans une file et exécutées les unes après les autres dans l’EDT.

  • Les composants graphiques sont thread unsafe. C’est une erreur fréquente de les manipuler depuis plusieurs threads. Les autres threads doivent soumettre leur code à exécuter à l’EDT pour éviter les incohérences.

Structure d’une fenêtre

Hiérarchie de conteneurs

Le nom des conteneurs de javax.swing commencent par J.

Chaque application graphique possède au moins un conteneur de haut-niveau:

  • JFrame (fenêtre)

  • JDialog (boîte de dialogue)

  • JApplet (fenêtre à intégrer dans une page web)

Ces conteneurs possèdent un panneau d’affichage (accessible par getContentPane(), setContentPane()) sur lequel vous pouvez disposer des composants (qui dérivent de JComponent).

Composants graphiques

Il existe de nombreux composants graphiques:
  • JPanel (conteneur générique léger)

  • JLabel (étiquette de texte)

  • JButton (bouton)

  • JTextField (champs texte pouvant être éditable)

  • JMenuBar (barre des menus)

Consultez l’API standard pour la liste des composants disponibles dans javax.swing.

Personnaliser le panneau d’affichage

Habituellement, on crée un nouveau panneau d’affichage de zéro en utilisant JPanel, puis on l’ajoute au conteneur de haut niveau (typiquement de type JFrame) avec setContentPane().

//Create a panel and add components to it.
JPanel contentPane = new JPanel();
contentPane.add(someComponent);
contentPane.add(anotherComponent);

topLevelContainer.setContentPane(contentPane);

Layout Manager

Il existe des modèles pour disposer les composants graphiques sur un panneau d’affichage:

  • java.awt.BorderLayout (répartition en 5 zones: haut, bas, gauche, droite, centre)

  • java.awt.FlowLayout (place les composants de gauche à droite, ligne par ligne)

  • java.awt.GridLayout (répartition en un tableau 2d régulier)

  • javax.swing.BoxLayout (place les composants les uns au-dessous des autres)

Consultez la page des layout managers pour avoir un aperçu de ces modèles.

Utiliser un Layout Manager

Le modèle par défaut est FlowLayout. Mais il est très simple d’en utiliser un autre en le passant en paramètre, soit au constructeur de JPanel, soit à la méthode setLayout().

JPanel contentPane = new JPanel(new BorderLayout());
//or:
//JPanel contentPane = new JPanel();
//contentPane.setLayout( new BorderLayout() );

contentPane.add(someComponent, BorderLayout.CENTER);
contentPane.add(anotherComponent, BorderLayout.PAGE_END);

topLevelContainer.setContentPane(contentPane);

Ex.1. Calculatrice/Structure (20 min)

Reproduisez la fenêtre suivante:

Capture d'ecran du modèle

Ex.1. Détails

  • Le panneau d’affichage principal utilise un BorderLayout.

  • En haut (PAGE_START), se trouve un JTextField.

  • En bas (PAGE_END), se trouve un JLabel.

  • A gauche (LINE_START), se trouve un JButton pour remettre la calculatrice à zéro.

  • A droite (LINE_END), se trouve un JButton pour afficher le résultat.

  • Au centre (CENTER), se trouve un panneau secondaire utilisant un GridLayout contenant des JButton pour les chiffres et les opérations.

  • Pensez à garder des références vers tous les composants.

Gestion des evénements

Fonctionnement général

  • A un composant graphique (JButton), on attache un objet capable d’écouter les événements (ActionListener).

  • Quand l’utilisateur réalise une action sur le composant (clic), un événement est généré (ActionEvent).

  • La machine virtuelle reçoit tous les événements, mais seul les événements écoutés déclenchent une réaction (dont le code se trouve dans la méthode actionPerformed() de l’interface ActionListener).

Exemple de Listener

import java.awt.event.ActionListener; 
import java.awt.event.ActionEvent; 

/*
 * Button listener
 */
public class ButtonBeeper implements ActionListener {

    @Override 
    public void actionPerformed(ActionEvent e) {
	//print 'beep' to the standard output
	//when an action event is received
	System.out.println("beep"); 
    }

}

Exemple d’application

import javax.swing.*;       
public class BeeperApp implements Runnable {
    @Override 
    public void run() {
        //Create the window.
        JFrame f = new JFrame("Beeper");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        // Add a button with an action listener
	JButton b = new JButton("Click me"); 
	b.addActionListener( new ButtonBeeper() ); 
        f.getContentPane().add(b);
	//Display the window.
        f.pack();
        f.setVisible(true);
    }
    public static void main(String[] args) {
	//Run the application at the correct time in the event queue.
        SwingUtilities.invokeLater( new BeeperApp() );  
    }
}

Quelques types d’évenement

  • ActionEvent / ActionListener (déclenchés par JButton)

  • ItemEvent / ItemListener (déclenchés par JCheckBox)

  • MouseEvent / MouseListener (déclenchés par la souris sur un composant)

  • KeyEvent / KeyListener (touche clavier)

Consultez l’API standard pour la liste des événements disponibles dans java.awt.event, le tutoriel Evénements, ainsi que les How To consacrés aux composants pour savoir quel type d’événement ils déclenchent.

ActionEvent / ActionListener

Le couple ActionEvent / ActionListener est le plus commun.

  • ActionEvent est la classe des événements déclenchés par une action bien définie sur un composant. Elle possède notamment la méthode getSource() pour obtenir le composant ayant déclenché l’événement.

  • Un objet issu d’une classe qui implémente l’interface ActionListener, doté de la méthode actionPerformed(), est attaché à un tel composant par la méthode addActionListener().

Ex.2. Calculatrice/Evenements (30 min)

  • Faites en sorte que votre calculatrice affiche le résultat d’une suite d’additions ou de soustractions données par des actions sur les différents boutons.

  • Téléchargez la classe Processeur qui se charge des calculs.

  • Ecrivez un listener par type de bouton (un pour les chiffres, le plus, le moins, le = et le C); chacun connaissant une instance de Processeur (calcul) et une instance de JTextField (affichage).

  • Astuce: les composants JButton et JTextField possèdent tous les deux les méthodes getText() et setText() pour respectivement lire et écrire le texte attaché au composant.

Ce qu’il faut retenir

  • Une fenêtre (JFrame) est composée d’une hiérarchie de conteneurs (JPanel), contenant eux-même des composants graphiques élémentaires (JLabel, JButton, etc.).

  • Des modèles (layout managers) permettent de disposer les composants sur un panneau d’affichage.

  • Les composants graphiques peuvent s’abonner à des listeners (ActionListener), écoutant des événements particuliers. Lorsqu’un énénement écouté (ActionEvent) est déclenché, le code associé au listeners est exécutée par le Event-Dispatching Thread.

Ce que vous devez savoir faire

Réaliser une application graphique qui réagit aux actions de l’utilisateur.