Création interface graphique avec Swing : les bases


précédentsommairesuivant

3. Les fenêtres

Il existe plusieurs types de fenêtres dans Swing :

  • JWindow : C'est la fenêtre la plus basique. C'est juste un conteneur que vous pouvez afficher sur votre écran. Il n'a pas de barre de titre, pas de boutons de fermeture/redimensionnement et n'est pas redimensionnable par défaut. Vous pouvez bien sûr lui ajouter toutes ces fonctionnalités. On utilise surtout les JWindow pour faire des SplashScreen, c'est-à-dire des interfaces d'attente qui se ferment automatiquement.
  • JDialog : C'est une fenêtre destinée aux boîtes de dialogue. Ce type de fenêtre peut être modal, c'est-à-dire qu'elle bloque une autre fenêtre tant qu'elle est ouverte. Elles sont destinées à travailler de pair avec la fenêtre principale que nous allons voir maintenant.
  • JFrame : C'est une fenêtre destinée à être la fenêtre principale de votre application. Elle n'est dépendante d'aucune autre fenêtre et ne peut pas être modale. Elle a une barre de titre et peut accueillir une barre de menu. Elle possède un bouton de fermeture, un bouton de redimensionnement et un bouton pour l'iconifier.

Nous allons maintenant voir comment créer ces fenêtres sans trop entrer dans les détails pour cet article.

3.1. JWindow

Nous allons maintenant créer une simple JWindow qui ne fait rien pour le moment. Comme tel, ça n'est pas très utile, mais cela vous montrera à quoi ressemble une telle fenêtre.

Voici donc le code minimal nécessaire à la création d'une JWindow :

 
Sélectionnez
JWindow window = new JWindow();

On s'est donc juste contenté d'instancier une nouvelle JWindow. Maintenant pour l'afficher, on va utiliser la méthode setVisible qui vient de la classe Component et qui sera donc la même pour toutes les sortes de fenêtres.

 
Sélectionnez
SwingUtilities.invokeLater(new Runnable(){
	public void run(){
		//On crée une nouvelle instance de notre JWindow
		JWindow window = new JWindow(); 
		window.setSize(300, 200);//On lui donne une taille pour qu'on puisse la voir
		window.setVisible(true);//On la rend visible
	}
});

Comme vous pouvez le voir, c'est un peu plus compliqué que ce qu'on pense, mais rassurez-vous, vous allez vite comprendre à quoi sert tout ce code. En plus, certains me diront que ça marche sans tout ça. Oui, en effet, ça marche sans ça, mais dans ce tutoriel nous allons tout de suite apprendre la bonne façon de faire et c'est celle-ci

Alors, pourquoi tout ce code ? Pour une raison bien simple, Swing utilise son propre thread de traitement, qu'on appelle l'EDT (Event Dispatch Thread). C'est-à-dire que dans chaque application, on a 2 threads (au minimum), un thread pour le programme en lui-même et un thread pour Swing. La règle est simple, on ne fait rien de graphique dans le thread principal et on ne fait rien d'autres que du graphique dans le thread Swing. On crée donc une tâche (Runnable) contenant le code dédié à la création de la fenêtre et on l'ajoute dans le thread de Swing.

Un thread, c'est quoi ? Vous pouvez vous représentez un thread comme un fil d'éxécution. C'est-à-dire une sorte de tube contenant des instructions à effectuer. Quand vous voulez faire quelque chose dans le thread de Swing, vous allez rajouter un nouvel élément dans le tube et il va être exécuté quand ce sera son tour.

Pourquoi ne faut-il pas mélanger les deux ? Parce que si nous éxécutons une action longue dans l'EDT, nous bloquerons ce dernier et l'interface va être figée jusqu'à la fin de cette action. Tandis que si nous séparons les deux, on a notre action en tâche de fond et notre interface qui est toujours réactive.

Je ne vais pas m'étendre plus longtemps sur le sujet, si vous voulez plus d'informations, je vous invite à consulter cet excellent article : Threads et performance avec swing.

On va maintenant mettre notre code dans une méthode main :

 
Sélectionnez
public class TestJWindow {
	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable(){
			public void run(){
				//On crée une nouvelle instance de notre JWindow
				JWindow window = new JWindow();
				window.setSize(300, 200);//On lui donne une taille pour qu'on puisse la voir
				window.setVisible(true);//On la rend visible
			}
		});
	}
}

Mais on ne va pas le laisser tel quel, car sinon, on ne pourrait pas fermer notre programme. On va donc rajouter une attente de 5 secondes ensuite fermer le programme. Pour ceux qui ne le savent pas, pour attendre un certain temps, on utiliser la méthode statique sleep de la classe Thread et pour quitter le programme, on utilise la méthode exit de la classe System :

 
Sélectionnez
public class TestJWindow {
	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable(){
			public void run(){
				//On crée une nouvelle instance de notre JWindow
				JWindow window = new JWindow();
				window.setSize(300, 200);//On lui donne une taille pour qu'on puisse la voir
				window.setVisible(true);//On la rend visible
			}
		});
 
		try { 
			Thread.sleep(5000);
		} catch (InterruptedException e) {}
 
		System.exit(0);
	}
}

Et voici le résultat :

JWindow
JWindow

Comme vous le voyez, en l'état ce n'est pas très beau... C'est pour ça qu'il est assez rare de les utiliser, mis à part pour faire un écran de démarrage ou des fenêtres très personnalisés. Mais rassurez-vous, nous allons tout de suite passer à quelque chose de plus commun et de plus utile.

Le code complet : TestJWindow

3.2. JDialog

Passons maintenant à une JDialog. Encore une fois, nous allons créer une fenêtre toute vide, nous apprendrons plus loin comment faire pour ajouter quelques choses dans cette fenêtre.

Voilà donc le code minimal pour créer une JDialog avec un titre :

 
Sélectionnez

JDialog dialog = new JDialog();
dialog.setTitle("Première fenêtre"); //On lui donne un titre

C'est une nouvelle fois tout simple, non ?

On remet notre code dans un main :

 
Sélectionnez

public class TestJDialog {
	public static void main(String[] args){
		SwingUtilities.invokeLater(new Runnable(){
			public void run(){
				//On crée une nouvelle instance de notre JDialog
				JDialog dialog = new JDialog();
				dialog.setSize(300, 200);//On lui donne une taille
				dialog.setTitle("Première fenêtre"); //On lui donne un titre
				dialog.setVisible(true);//On la rend visible
				setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //On dit à l'application de se fermer lors du clic sur la croix
			}
		});
	}
}

Vous pouvez voir que c'est très ressemblant au code de la JWindow. Le principe reste en effet le même pour toutes les fenêtres.

Voici donc ce que vous donne ce code :

JDialog
JDialog

Le résultat est déjà plus proche d'une fenêtre qu'on rencontre habituellement.

En général, on n'utilise pas directement la classe JDialog comme ça. On passe souvent par la classe JOptionPane qui permet de créer des boites de dialogue très facilement. Nous verrons cela au chapitre 8.

Le code complet : TestJDialog

3.3. JFrame

Passons maintenant à la fenêtre la plus complète et celle qui va nous intéresser le plus, la JFrame.

Cette fois, on ne va pas créer directement une instance de JFrame, mais on va créer une nouvelle classe héritant de JFrame. C'est-à-dire un nouveau type de JFrame si vous préférez. Il ne faut bien sûr pas oublier d'importer la classe JFrame.

Ainsi, vous pourriez faire quelque chose dans ce goût-là :

 
Sélectionnez
import javax.swing.JFrame;
 
public class SimpleFenetre extends JFrame{
 
	public SimpleFenetre(){
		super();
	}
}

Sauf qu'ainsi, on n'afficherait rien du tout, il va donc falloir ensuite configurer cette fenêtre pour qu'elle fasse ce que l'on veut. Pour cela, on va créer une méthode qui va initialiser notre fenêtre et appeler celle-ci depuis notre constructeur.

Voici donc ce à quoi va ressembler notre fenêtre :

 
Sélectionnez
import javax.swing.JFrame;
 
public class SimpleFenetre extends JFrame{
 
	public SimpleFenetre(){
		super();
 
		build();//On initialise notre fenêtre
	}
 
	private void build(){
		setTitle("Ma première fenêtre"); //On donne un titre à l'application
		setSize(320,240); //On donne une taille à notre fenêtre
		setLocationRelativeTo(null); //On centre la fenêtre sur l'écran
		setResizable(false); //On interdit la redimensionnement de la fenêtre
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //On dit à l'application de se fermer lors du clic sur la croix
	}
}

Voici ce que font les différentes méthodes que l'on vient d'utiliser :

  • setTitle(String title) : Cette méthode modifie le titre de la fenêtre. Ce titre va apparaître dans la barre de titre et également dans la barre des tâches.
  • setSize(int width, int height) : Cette méthode permet de modifier la taille de la fenêtre. On verra plus tard qu'il y une autre façon de faire pour changer la taille de la fenêtre, mais cette deuxième façon n'est utile que pour les fenêtres non vides.
  • setLocationRelativeTo(Component c) : Cette méthode permet de positionner la fenêtre par rapport à un composant. En indiquant un composant null, elle va se placer automatiquement au milieu de l'écran.
  • setResizable(boolean resizable) : Cette méthode permet ou non le redimensionnement de la fenêtre.
  • setDefaultCloseOperation(int operation) : Cette méthode permet de configurer l'action qui va être éxécutée lors de la fermeture de la fenêtre. On peut choisir de faire quitter le programme, de fermer la fenêtre ou de la rendre invisible (ce qui n'est pas pareil)

La méthode setLocationRelativeTo(null) pour centrer une fenêtre ne fonctionne pas avec plusieurs écrans. Elle va en effet centrer la fenêtre au milieu des deux écrans. Ce n'est pas un bug car elle positionne la fenêtre au milieu de l'espace affichable, mais ce n'est pas pratique. Si vous êtes dans un tel cas, je vous laisser consulter l'annexe à la fin de cet article.

Avec ces méthodes, vous devriez pouvoir commencer à créer vos propres fenêtres. Il existe bien sûr encore bien d'autres choses que l'on peut faire avec les fenêtres, mais ce n'est pas l'objet de cet article.

On va créer une classe (TestJFrame) qui va nous permettre de lancer notre code maintenant :

 
Sélectionnez
public class TestJFrame {
	public static void main(String[] args){
		SwingUtilities.invokeLater(new Runnable(){
			public void run(){
				//On crée une nouvelle instance de notre JDialog
				SimpleFenetre fenetre = new SimpleFenetre();
				fenetre.setVisible(true);//On la rend visible
			}
		});
	}
}

A nouveau le code est semblable à celui des autres fenêtres, sauf que cette fois-ci on n'instancie pas directement un fenêtre Swing mais notre propre fenêtre.

Et voici ce que donne le code que l'on a développé :

JFrame
JFrame

La seule différence visuelle avec la JDialog est le nombre de boutons. Sur la JDialog on n'a que le bouton de fermeture alors qu'avec la JFrame, on peut minimiser la fenêtre ou la réduire dans la barre des tâches.

Code complet :

3.4. Application au projet

Maintenant que l'on sait créer une fenêtre, on va commencer notre projet de calculatrice. La fenêtre que l'on doit développer est la fenêtre principale de notre application. On va donc utiliser une JFrame. Pour le moment, on va fixer la taille de notre JFrame à 400 sur 200, on l'adaptera plus tard en fonction de nos composants. Cette fenêtre portera comme titre "Calculatrice", sera centrée à l'écran, ne sera pas redimensionnable et fermera l'application lors de la fermeture de la fenêtre.

Essayez de réfléchir à la solution avant de regarder. C'est vraiment très simple, mais c'est toujours mieux si c'est vous qui le faites.

Voici ce que pourrait donner notre code :

 
Sélectionnez
import javax.swing.JFrame;
 
public class CalculatriceFenetre extends JFrame{
 
	public CalculatriceFenetre(){
		super();
 
		build();//On initialise notre fenêtre
	}
 
	private void build(){
		setTitle("Calculatrice"); //On donne un titre à l'application
		setSize(400,200); //On donne une taille à notre fenêtre
		setLocationRelativeTo(null); //On centre la fenêtre sur l'écran
		setResizable(false); //On interdit la redimensionnement de la fenêtre
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //On dit à l'application de se fermer lors du clic sur la croix
	}
}

Comme vous le voyez, je n'ai pas mis de méthode main dans cette classe. On va en effet mettre cette méthode dans une classe lanceur qui sera la classe principale. Pensez à toujours correctement séparer les responsabilités de vos objets dans des classes différentes. On va donc créer une classe Calculatrice qui va lancer notre fenêtre :

 
Sélectionnez
public class Calculatrice {
	public static void main(String[] args){
		SwingUtilities.invokeLater(new Runnable(){
			public void run(){
				CalculatriceFenetre fenetre = new CalculatriceFenetre();
				fenetre.setVisible(true);
			}
		});
	}
}

Et une fois cette classe lancée, vous devriez voir notre application se lancer :

Notre calculatrice
Notre calculatrice

Elle est encore toute simple et ne contient rien, mais on a déjà la fenêtre qui s'affiche.

Code complet :


précédentsommairesuivant

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2009 Baptiste Wicht. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.