Programmation Java Swing/Fenêtres
Les fenêtres Swing dérivent de celles disponibles avec AWT :
Points communs.
Les différents types de fenêtres Swing cités précédemment ont une structure commune et des méthodes communes.
L'exemple ci-dessous crée une fenêtre d'application avec un titre, contenant un label affichant du texte.
package org.wikibooks.fr.swing;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
 * Créer une fenêtre. 
 * @author fr.wikibooks.org
public class ExempleFenetre extends JFrame
 public ExempleFenetre()
 // Création de la fenêtre
 setTitle("Démonstration de création de fenêtre Swing");
 Dimension d = new Dimension(500, 200);
 setMinimumSize(d);
 setSize(d);
 Container c = getContentPane();
 c.setLayout(new FlowLayout());
 JLabel l_texte = new JLabel("La fenêtre est ouverte");
 c.add(l_texte);
 public static void main(String[] args)
 EventQueue.invokeLater(new Runnable()
 public void run()
 ExempleFenetre frame = new ExempleFenetre();
 frame.setVisible(true);
 });
Titre et icône.
Une fenêtre possède un titre (méthode codice_2) et une icône (méthode codice_3).
Par défaut, l'icône est la même que celle de la fenêtre propriétaire.
Composition.
Chaque fenêtre comporte un panel racine (classe JRootPane) qui gère la composition des éléments suivants :
La barre de menu et le panneau de contenu sont gérés par un panneau de classe JLayeredPane permettant de gérer la superposition de composants.
Taille et position.
La taille et la position d'une fenêtre sont gérées avec les mêmes méthodes que celles des composants.
Il n'y a pas de gestionnaire de disposition pour les fenêtres, car aucun conteneur ne les contient (hormis JInternalFrame et JApplet).
La taille et la position de la fenêtre définies par l'application peuvent ensuite être modifiées par l'utilisateur en déplaçant et en redimensionnant la fenêtre.
Les méthodes codice_4 et codice_5 définissent les limites du redimensionnement.
La méthode codice_6 héritée de la classe codice_7 n'a pas de sens pour les fenêtres.
Menu.
Les fenêtres de type codice_8 et codice_9 peuvent avoir une barre de menus.
Voir le chapitre suivant sur les menus pour plus de détails.
Fenêtre d'application.
La fenêtre d'application est celle qui définie la vue principale d'une application.
Une application peut en avoir plusieurs (Par exemple, une fenêtre par fichier ouvert).
Les applications les plus simples n'ont qu'une seule fenêtre principale.
La classe codice_8 définit une fenêtre d'application.
Action de fermeture.
La méthode codice_11 définit l'action effectuée quand l'utilisateur clique le bouton de fermeture de la fenêtre.
L'argument peut avoir l'une des valeurs suivantes définies dans l'interface codice_12 implémentée par la classe codice_13 :
Par défaut, la valeur est codice_15.
Tout changement provoque un évènement de changement de propriété dont le nom est codice_20.
Quand la dernière fenêtre est libérée (dispose), l'application peut se terminer.
Quand l'application doit faire confirmer la fermeture par l'utilisateur (par exemple en cas de données non sauvegardées), il est nécessaire de définir l'action de fermeture à rien (codice_14) et d'ajouter un écouteur d'évènements des fenêtres (interface codice_22 implémentée par la classe vide codice_23).
Dans le constructeur de la classe de fenêtre principale :
addWindowListener(new WindowAdapter()
 @Override
 public void windowClosing(WindowEvent e)
 fermerFenetre();
});
Dans la classe de fenêtre principale :
// Indicateur de données modifiées depuis la dernière sauvegarde
private boolean donnees_modifiees = false;
// Assigné à false par les actions suivantes :
// - création d'un nouveau fichier,
// - chargement à partir d'un fichier,
// - enregistrement des données.
// Assigné à true par toute action modifiant les données.
// Pour confirmer une action faisant perdre les données
private boolean confirmerAction(String action)
 if (donnees_modifiees)
 int reponse = JOptionPane.showConfirmDialog(this,
 "Attention ! Les données n'ont pas été sauvegardées.\n"+
 action+" maintenant provoquera une perte de données.\n"+
 "Continuer et perdre les données ?",
 "Confirmer la perte de données",
 JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
 return reponse == JOptionPane.YES_OPTION;
 else return true; // On peut effectuer l'action
private void fermerFenetre()
 if (confirmerAction("Quitter l'application"))
 // Fermer la fenêtre et quitter
 dispose();
 System.exit(0);
La méthode codice_24 ci-dessus est réutilisable pour les actions provoquant une perte des données non sauvegardées :
États de la fenêtre.
La méthode codice_25 permet de modifier l'état de la fenêtre, et la méthode codice_26 permet de récupérer l'état actuel :
Icône de fenêtre.
L'icône de la fenêtre d'application est visible, selon le système d'exploitation, dans le coin du bord de la fenêtre (sous Windows, en haut à gauche en 16x16 pixels), dans la barre des tâches (taille variable : 16x16, 48x48, 64x64, ...), dans le sélecteur de fenêtres (sous Windows avec ou ).
L'icône de la fenêtre d'application peut aussi être utilisée par les boîtes de dialogue ayant la fenêtre comme propriétaire ("owner") passé au constructeur.
Deux méthodes existent :
La méthode codice_32 est en fait un appel à la méthode codice_33 en lui passant une liste contenant une seule image.
En général, l'icône est une image stockée dans le même répertoire que les classes de l'application, dans un format supporté par codice_36 (PNG, GIF).
Exemple pour une image stockée dans le même répertoire que la classe de la fenêtre :
 * Créer la fenêtre principale.
 * @throws IOException Erreur de lecture de ressource interne.
public MainWindow() throws IOException
 Image image_icon = ImageIO.read(MainWindow.class.getResource("icone_application.png"));
 setIconImage(image_icon);
Pour une liste d'icônes :
public MainWindow() throws IOException
 List<Image> liste_icones = new ArrayList<>();
 liste_icones.add(ImageIO.read(MainWindow.class.getResource("icone_application_16.png"))); // 16x16
 liste_icones.add(ImageIO.read(MainWindow.class.getResource("icone_application_48.png"))); // 48x48
 liste_icones.add(ImageIO.read(MainWindow.class.getResource("icone_application_64.png"))); // 64x64
 setIconImages(liste_icones);
Fenêtre de dialogue.
Une fenêtre de dialogue est une fenêtre temporaire ouverte sur une action spécifique permettant de dialoguer avec l'utilisateur pour lui fournir et lui demander une ou plusieurs informations : entrer les champs d'une nouvelle entité à ajouter dans une table, sélectionner un fichier, sélectionner une couleur, afficher un message d'erreur, demander une confirmation de suppression...
Fenêtres de dialogue prédéfinies.
Swing possède des classes ou méthodes permettant d'utiliser des fenêtres de dialogue prédéfinies.
Fenêtre de dialogue de type message : JOptionPane.
La classe codice_37 définit une fenêtre de dialogue simple permettant d'afficher un message avec une icône prédéfinie associée, pouvant avoir un champ de saisie selon le type, et proposant plusieurs choix de bouton.
Simple notification de message.
Ce type de fenêtre affiche simplement le message et possède un bouton OK pour fermer la fenêtre, et utilise la méthode codice_41.
Exemple :
JOptionPane.showMessageDialog(frame,
 "Une erreur s'est produite pour illustrer cette section.\nUne seconde ligne d'information.",
 "Erreur de démonstration", JOptionPane.ERROR_MESSAGE);
JOptionPane.showMessageDialog(frame,
 "Un avertissement signale un fait important porté à l'attention de l'utilisateur.",
 "Avertissement de démonstration", JOptionPane.WARNING_MESSAGE);
JOptionPane.showMessageDialog(frame,
 "Une information pour l'utilisateur.",
 "Information de démonstration", JOptionPane.INFORMATION_MESSAGE);
JOptionPane.showMessageDialog(frame,
 "Un message pour l'utilisateur, sans icône.",
 "Message de démonstration", JOptionPane.PLAIN_MESSAGE);
// Le type question est plus pertinent pour les autres types de fenêtres où l'utilisateur peut choisir une réponse.
JOptionPane.showMessageDialog(frame,
 "Une question pour l'utilisateur, mais il ne peut répondre que OK.",
 "Des questions ?", JOptionPane.QUESTION_MESSAGE);
Il existe deux variantes de la méthode codice_41 :
Message en HTML.
Il est possible d'utiliser le format HTML pour formater le message affiché.
Pour cela, il faut encadrer le message dans une balise codice_49 et ne pas utiliser de caractères de contrôle dans le message ; par exemple codice_50 qui doit être remplacé par codice_51.
Exemple :
JOptionPane.showMessageDialog(frame,
 "<html>Une erreur s'est produite pour illustrer cette section.<br/>" +
 "<b>Ceci est une information importante.</b></html>",
 "Erreur de démonstration", JOptionPane.ERROR_MESSAGE);
Pour plus de détails sur le formatage en HTML et les limitations, voir le chapitre sur le contenu en HTML.
Fenêtre de confirmation.
Ce type de fenêtre affiche le message et propose plusieurs boutons de confirmation pour fermer la fenêtre, et utilise la méthode codice_52.
Exemple :
int reponse = JOptionPane.showConfirmDialog(frame,
 "Confirmez-vous vouloir fermer la fenêtre sans sauvegarder ?",
 "Modifications non sauvegardées",
 JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE);
Les variantes de la méthode sont :
Fenêtre de saisie.
Ce type de fenêtre utilise la méthode codice_63 et affiche le message et un champ de saisie ou une liste de choix, et les boutons OK et Cancel pour fermer la fenêtre.
Exemple :
String choix = JOptionPane.showInputDialog(frame,
 "Choisissez un nom pour le projet",
 "Choisir un nom",
 JOptionPane.QUESTION_MESSAGE,
 null, // Pas d'icône personnalisée
 new Object[]{ // Choix possible
 "Wikilivres",
 "Wikipédia",
 "Wiktionnaire",
 null // null pour autoriser l'utilisateur à entrer une autre valeur
 // Par défaut :
 "Wikilivres");
La méthode retourne la valeur sélectionnée ou entrée par l'utilisateur, ou codice_44 si l'utilisateur a choisi d'annuler.
Panel de dialogue interne.
Les méthodes vu précédemment ont toutes une variante pour afficher un panel de dialogue interne, dont le nom est celui de la méthode où codice_65 est remplacé par codice_66 :
Fenêtre de sélection de couleur : JColorChooser.
La fenêtre de sélection de couleur permet de choisir une couleur parmi une palette prédéfinie ou en spécifiant les composantes RVB ou TSL.
Les arguments de la méthode codice_71 de la classe codice_38 sont :
La méthode retourne la couleur sélectionnée de classe codice_73 ou codice_44 si l'utilisateur a annulé.
Exemple : Sélection de la couleur de fond :
Color c_fond = Color.BLACK;
Color c = JColorChooser.showDialog(frame, "Sélectionnez la couleur de fond", c_fond);
if (c != null)
 c_fond = c;
 setBackground(c); // ... ou autre mise à jour de couleur
Fenêtre de sélection de fichier ou répertoire : JFileChooser.
La classe codice_39 définit une fenêtre permettant de sélectionner un ou plusieurs fichiers, ou un répertoire.
Exemple : Sélection pour ouvrir un fichier.
protected File selectionFichierOuvrir()
 // Création
 JFileChooser jfc = new JFileChooser();
 // Sélection pour ouvrir un fichier :
 int res = jfc.showOpenDialog(frame); // Retourne le bouton cliqué
 return (res == JFileChooser.APPROVE_OPTION) ? jfc.getSelectedFile() : null;
Exemple : Sélection pour enregistrer un fichier.
protected File selectionFichierEnregistrer()
 // Création
 JFileChooser jfc = new JFileChooser();
 // Sélection pour enregistrer un fichier :
 int res = jfc.showSaveDialog(frame); // Retourne le bouton cliqué
 return (res == JFileChooser.APPROVE_OPTION) ? jfc.getSelectedFile() : null;
Pour conserver le répertoire courant à chaque réouverture, il vaut mieux que l'instance de la classe codice_39 soit déclarée dans la classe et construit par le constructeur.
// Création
JFileChooser jfc = new JFileChooser();
protected File selectionFichierOuvrir()
 // Sélection pour ouvrir un fichier :
 int res = jfc.showOpenDialog(frame); // Retourne le bouton cliqué
 return (res == JFileChooser.APPROVE_OPTION) ? jfc.getSelectedFile() : null;
protected File selectionFichierEnregistrer()
 // Sélection pour enregistrer un fichier :
 int res = jfc.showSaveDialog(frame); // Retourne le bouton cliqué
 return (res == JFileChooser.APPROVE_OPTION) ? jfc.getSelectedFile() : null;
Fichier présélectionné.
Avant l'affichage, on peut changer le répertoire courant et/ou le fichier sélectionné :
// Initialise le fichier sélectionné :
jfc.setSelectedFile(new File("/etc/config/wikilivres.fr.cfg"));
int res = jfc.showOpenDialog(frame); // Retourne le bouton cliqué
// Initialiser le répertoire courant :
jfc.setCurrentDirectory(new File("/etc/config"));
int res = jfc.showOpenDialog(frame); // Retourne le bouton cliqué
Sélectionner plusieurs fichiers.
Il est possible d'autoriser la sélection de plusieurs fichiers :
protected File[] selectionPlusieursFichiersOuvrir()
 jfc.setMultiSelectionEnabled(true);
 int res = jfc.showOpenDialog(frame); // Retourne le bouton cliqué
 return (res == JFileChooser.APPROVE_OPTION) ? jfc.getSelectedFiles() : null; // getSelectedFiles au pluriel
Sélectionner un fichier ou un répertoire.
Le mode de sélection permet de choisir si l'utilisateur peut sélectionner un fichier, un répertoire ou les deux :
jfc.setFileSelectionMode(JFileChooser.FILES_ONLY);
jfc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
jfc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
Filtres de fichier.
La fenêtre de sélection possède deux types de filtre de classe codice_77 :
Le filtre général de la vue est configuré en appelant la méthode codice_78.
Exemple :
jfc.setFilter(new javax.swing.filechooser.FileFilter()
 @Override
 public boolean accept(File f)
 return f.getName().toLowerCase().endsWith(".wiki") || f.isDirectory();
 @Override
 public String getDescription()
 return "Wiki source file"; // Description non utilisée pour le filtre général
 });
Les filtres sélectionnables sont ajoutés un par un en appelant la méthode codice_79.
Exemple :
jfc.addChoosableFileFilter(new javax.swing.filechooser.FileFilter()
 @Override
 public boolean accept(File f)
 return f.getName().toLowerCase().endsWith(".wiki");
 @Override
 public String getDescription()
 return "Wiki source file"; // Description utilisée dans la liste de choix.
 });
Vous pouvez utiliser la sous-classe codice_80 pour les filtres basés sur l'extension de fichier.
Le constructeur prend en paramètre la description du filtre suivie de la liste des extensions de nom des fichiers acceptés :
FileFilter file_filter_image = new FileNameExtensionFilter("Image d'illustration", "png","bmp","jpeg","jpg","gif");
Ajouter une prévisualisation.
La fenêtre de sélection de fichiers peut afficher un composant accessoire pour, par exemple, afficher un aperçu du fichier sélectionné (image, ...).
Pour ajouter un tel composant, il faut utiliser la méthode codice_81.
Exemple : Une vue de prévisualisation d'image :
import java.awt.*;
import java.beans.*;
import java.io.*;
import javax.imageio.*;
import javax.swing.*;
public class FilePreview extends JPanel
implements PropertyChangeListener
 // Largeur maximale de prévisualisation :
 private static final int PREF_IMAGE_WIDTH = 150;
 // Marge en pixels :
 private static final int MARGIN = 5;
 public FilePreview()
 setPreferredSize(new Dimension(PREF_IMAGE_WIDTH+MARGIN, -1));
 // Méthode de l'interface PropertyChangeListener appelée
 // quand une propriété est modifiée, pour mettre à jour
 // la prévisualisation quand le fichier sélectionné change.
 public void propertyChange(PropertyChangeEvent e)
 String property_name = e.getPropertyName();
 if (property_name.equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY))
 File selection = (File)e.getNewValue();
 updateView(selection == null ? null : selection.getAbsolutePath());
 private int width, height, xi,yi;
 private Image image, scaled_image=null;
 public static Image getImage(String p)
 if (p==null) return null;
 return getImage(new File(p));
 public static Image getImage(File fpath)
 if (fpath==null) return null;
 catch (IOException e) { } // Ignorer l'erreur, ne pas afficher d'image.
 return null;
 protected void updateView(String name)
 info = DEFAULT_INFO;
 image = getImage(name);
 if (image == null && name!=null) info = "Le fichier sélectionné n'est pas une image";
 scaled_image = null;
 repaint();
 @Override
 public void setBounds(int x, int y, int width, int height)
 scaled_image = null;
 super.setBounds(x, y, width, height);
 private static final String DEFAULT_INFO = "Pas d'image sélectionnée";
 private String info = DEFAULT_INFO; // Information sur l'image
 private void scaleImage(Dimension dd)
 xi = MARGIN; yi = 0; // Position du cadre virtuel de l'image
 Dimension d = new Dimension(dd.width-MARGIN, dd.height-20);
 width = image.getWidth(this);
 height = image.getHeight(this);
 info = (width<0||height<0)?DEFAULT_INFO:""+width+"x"+height+" pixels";
 // Mise à l'échelle de l'image si besoin
 // et centrage dans le cadre virtuel :
 if ((d.width==width)&&(d.height==height))
 scaled_image = image;
 else if (width*d.height >= height*d.width)
 height = height * d.width / width;
 width = d.width;
 scaled_image = image.getScaledInstance(width, height, Image.SCALE_SMOOTH);
 yi+=(d.height-height)/2;
 else
 width = width * d.height / height;
 height = d.height;
 scaled_image = image.getScaledInstance(width, height, Image.SCALE_SMOOTH);
 xi+=(d.width-width)/2;
 public void paintComponent(Graphics g)
 super.paintComponent(g);
 Dimension d = getSize(); if (d==null) return;
 if ((scaled_image == null)&&(image!=null)) scaleImage(d);
 g.setColor(getBackground());
 g.fillRect(0, 0, d.width, d.height);
 if (scaled_image!=null)
 g.drawImage(scaled_image, xi, yi, this);
 g.setColor(Color.BLACK);
 g.drawString(info, MARGIN, d.height-5);
Une instance de cette classe s'ajoute en appelant les deux méthodes ci-dessous :
FilePreview fp = new FilePreview();
jfc.setAccessory(fp); // Pour l'afficher
jfc.addPropertyChangeListener(fp); // Pour écouter le changement de fichier sélectionné