Niveau : | Intermédiaire |
SWT est une API de bas niveau. Elle propose des objets qui permettent la création d'interfaces graphiques mais qui nécessitent aussi énormément de code.
JFace propose d'encapsuler de nombreuses opérations de base et de faciliter ainsi le développement des interfaces graphiques reposant sur SWT.
Ce chapitre contient plusieurs sections :
L'API de JFace est indépendante du système graphique utilisé : la dépendance est réalisée par SWT sur lequel JFace repose.
JFace est une bibliothèque qui facilite l'utilisation de SWT dans le développement d'applications standalones. Elle encapsule un certain nombre de traitements et réduit ainsi la quantité de code à produire.
L'utilisation de JFace n'est pas obligatoire mais sans celle-ci un certain nombre de fonctionnalités proposées par cette API seraient à redévelopper.
JFace n'est fournie en standard qu'avec Eclipse car la partie IHM d'Eclipse est développée avec elle. Cependant elle peut être utilisée dans une application standalone si toutes les bibliothèques requises sont copiées à partir d'Eclipse.
Ces bibliothèques sous la forme de fichiers .jar sont réparties dans plusieurs sous-répertoires du répertoire plug-in d'Eclipse :
Fichier .jar |
Sous-répertoire |
jface.jar |
org.eclipse.jface_3.0.0 |
jfacetext.jar |
org.eclipse.jface.text_3.0.0 |
osgi.jar |
org.eclipse.osgi_3.0.0 |
runtime.jar |
org.eclipse.core.runtime_3.0.0 |
text.jar |
org.eclipse.text_3.0.0 |
Toutes les bibliothèques doivent être ajoutées dans le classpath de l'application.
Comme JFace repose sur SWT, il est aussi nécessaire d'ajouter la ou les bibliothèques requises par SWT notamment le fichier swt.jar et paramétrer l'application pour qu'elle puisse accéder à la bibliothèque native de SWT. Pour plus de détails, consultez le chapitre sur l'utilisation de SWT.
Une application utilisant JFace hérite de la classe ApplicationWindow. Cette classe encapsule un objet de type Shell de SWT.
Elle propose plusieurs méthodes :
Méthodes |
Rôle |
run() |
traitements exécutés par l'application |
createContents() |
renvoie le composant qui sera affiché dans la fenêtre de l'application |
La méthode run() est fréquemment la même :
L'appel de ces trois méthodes remplace la création d'un objet de Shell et l'écriture de la boucle de traitement des événements nécessaire en SWT.
Le booléen passé en paramètre de la méthode setBlockOnOpen() permet simplement de préciser si la méthode doit utiliser ou non la boucle de traitement des événements.
La méthode open() assure l'initialisation et le traitement des événements
La dernière étape permettant la libération des ressources de l'objet Display courant est nécessaire car elle n'est pas réaliser par la méthode open().
Exemple : |
import org.eclipse.jface.window.ApplicationWindow;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
public class TestJFace1 extends ApplicationWindow {
public TestJFace1() {
super(null);
}
public void run() {
setBlockOnOpen(true);
open();
Display.getCurrent().dispose();
}
protected Control createContents(Composite parent) {
Label label = new Label(parent, SWT.CENTER);
label.setText("Bonjour");
return label;
}
public static void main(String[] args) {
new TestJFace1().run();
}
}
Les boîtes de dialogue proposées par JFace ne remplacent pas celles proposées en standard par SWT. Elles ajoutent d'autres fonctionnalités notamment pour répondre aux besoins particuliers d'Eclipse.
Toutes les classes de ces boîtes de dialogue sont regroupées dans le package org.eclipse.jface.dialogs.
JFace propose une boîte de dialogue dédiée à l'affichage de messages d'erreurs. Cette classe est spécifiquement étudiée pour les besoins d'Eclipse dans la mesure où elle utilise un objet de type IStatus.
L'interface IStatus définit les méthodes qui encapsulent une erreur ou une série d'erreurs.
Un status nécessite un code de sévérité. Plusieurs constantes sont définies dans l'interface IStatus
Pour instancier un status, il est nécessaire d'utiliser le seul et unique constructeur de la classe Status qui attend en paramètre :
La classe ErrorDialog possède une méthode statique openError() qui attend en paramètres :
Exemple : |
import org.eclipse.jface.dialogs.*;
import org.eclipse.jface.window.ApplicationWindow;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.events.*;
import org.eclipse.core.runtime.*;
public class TestJFace2 extends ApplicationWindow {
public TestJFace2() {
super(null);
}
public void run() {
setBlockOnOpen(true);
open();
Display.getCurrent().dispose();
}
protected Control createContents(Composite parent) {
Button boutonAfficher = new Button(parent, SWT.PUSH);
boutonAfficher.setText("Afficher");
boutonAfficher.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
Status status = new Status(IStatus.ERROR, "plugin", 0,
"Raison de l'erreur", null);
ErrorDialog.openError(Display.getCurrent().getActiveShell(), "Erreur",
"Mon message d'erreur", status);
}
});
return boutonAfficher;
}
public static void main(String[] args) {
new TestJFace2().run();
}
}
JFace propose une boîte de dialogue permettant d'afficher un message aux utilisateurs encapsulé dans la classe MessageDialog.
Cette classe encapsule dans différentes méthodes statiques les boîtes de dialogue équivalentes proposées par SWT. Ceci permet de les utiliser avec une seule ligne de code.
Le plus simple pour utiliser cette classe est de faire appel à ses méthodes statiques qui attendent trois paramètres :
Exemple : |
import org.eclipse.jface.dialogs.*;
import org.eclipse.jface.window.ApplicationWindow;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.events.*;
public class TestJFace3 extends ApplicationWindow {
public TestJFace3() {
super(null);
}
public void run() {
setBlockOnOpen(true);
open();
Display.getCurrent().dispose();
}
protected Control createContents(Composite parent) {
Button boutonAfficher = new Button(parent, SWT.PUSH);
boutonAfficher.setText("Afficher");
final Shell shell = parent.getShell();
boutonAfficher.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
boolean reponse = false;
MessageDialog.openInformation(shell, "Information", "Le message d'information");
MessageDialog.openWarning(shell, "Avertissement", "Le message d'avertissement");
MessageDialog.openError(shell, "Erreur",
"Mon message d'erreur\n\nSeconde ligne du message");
reponse = MessageDialog.openConfirm(shell, "Confirmation",
"Le message de la confirmation");
System.out.println("reponse a la confirmation = " + reponse);
reponse = MessageDialog.openQuestion(shell, "question",
"Le message de la question");
System.out.println("reponse a la question = " + reponse);
}
});
return boutonAfficher;
}
public static void main(String[] args) {
new TestJFace3().run();
}
}
JFace propose une boîte de dialogue, encapsulée dans la classe InputDialog, qui permet de demander à l'utilisateur la saisie d'une donnée.
Cette classe possède un constructeur qui attend en paramètre :
L'appel à la méthode open() permet d'afficher la boîte de dialogue. La valeur retournée par cette méthode est soit Window.OK soit Window.CANCEL en fonction du bouton cliqué par l'utilisateur.
La méthode getValue() permet d'obtenir la valeur saisie par l'utilisateur si celui-ci a cliqué sur le bouton OK sinon elle renvoie null.
Exemple : |
import org.eclipse.jface.dialogs.*;
import org.eclipse.jface.window.*;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.events.*;
public class TestJFace4 extends ApplicationWindow {
public TestJFace4() {
super(null);
}
public void run() {
setBlockOnOpen(true);
open();
Display.getCurrent().dispose();
}
protected Control createContents(Composite parent) {
Button boutonAfficher = new Button(parent, SWT.PUSH);
boutonAfficher.setText("Afficher");
final Shell shell = parent.getShell();
boutonAfficher.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
int reponse = 0;
InputDialog inputDialog = new InputDialog(Display.getCurrent().getActiveShell(),
"Titre de la boite de dialogue",
"Saisissez la valeur", "test", null);
reponse = inputDialog.open();
if (reponse == Window.OK) {
System.out.println("Valeur saisie = " + inputDialog.getValue());
} else {
System.out.println("Operation annulée");
}
}
});
return boutonAfficher;
}
public static void main(String[] args) {
new TestJFace4().run();
}
}
Une particularité intéressante de cette boîte de dialogue est de pouvoir procéder à une validation des données au fur et à mesure de leur saisie.
Pour cela il faut définir un objet de type IInputValidator. Cette interface définit une unique méthode nommée isValid() qui possède en paramètre la valeur saisie courante et renvoie une chaîne de caractères qui contient un message d'erreur si la valeur n'est pas correcte. Si elle est correcte, il suffit de renvoyer null.
Une fois cette classe définie, il suffit de passer au dernier paramètre du constructeur de la classe InputDialog une instance de la classe réalisant la validation.
Exemple : |
import java.lang.reflect.InvocationTargetException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.operation.IRunnableWithProgress;
public class MonTraitement implements IRunnableWithProgress {
private static final int NB_ITERATION = 100;
public void run(IProgressMonitor monitor) throws InvocationTargetException,
InterruptedException {
monitor.beginTask("Exécution des traitements", NB_ITERATION);
for (int nb = 0; nb < NB_ITERATION && !monitor.isCanceled(); nb++) {
Thread.sleep(100);
monitor.worked(1);
monitor.subTask("Avancement : " + nb + " %");
}
monitor.done();
if (monitor.isCanceled())
throw new InterruptedException("Les traitements ont été interrompus");
}
}
Exemple : |
import java.lang.reflect.InvocationTargetException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.operation.IRunnableWithProgress;
public class MonTraitementInconnu implements IRunnableWithProgress {
private static final int NB_ITERATION = 100;
public void run(IProgressMonitor monitor) throws InvocationTargetException,
InterruptedException {
monitor.beginTask("Lancement des traitements", IProgressMonitor.UNKNOWN);
for (int nb = 0; nb < NB_ITERATION && !monitor.isCanceled(); nb++) {
Thread.sleep(100);
}
monitor.done();
if (monitor.isCanceled())
throw new InterruptedException("Les traitements ont été interrompus");
}
}
Exemple : |
import java.lang.reflect.InvocationTargetException;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.window.ApplicationWindow;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class TestJFace5 extends ApplicationWindow {
public TestJFace5() {
super(null);
}
public void run() {
setBlockOnOpen(true);
open();
Display.getCurrent().dispose();
}
protected Control createContents(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
composite.setLayout(new RowLayout(SWT.VERTICAL));
Button boutonExecuterD = new Button(composite, SWT.PUSH);
boutonExecuterD.setText("Exécuter déterminé");
final Shell shell = parent.getShell();
boutonExecuterD.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
try {
new ProgressMonitorDialog(shell).run(true, true, new MonTraitement());
} catch (InvocationTargetException e) {
MessageDialog.openError(shell, "Erreur", e.getMessage());
} catch (InterruptedException e) {
MessageDialog.openInformation(shell, "Interruption", e.getMessage());
}
}
});
Button boutonExecuterU = new Button(composite, SWT.PUSH);
boutonExecuterU.setText("Exécuter indéterminé");
boutonExecuterU.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
try {
new ProgressMonitorDialog(shell).run(true, true, new MonTraitementInconnu());
} catch (InvocationTargetException e) {
MessageDialog.openError(shell, "Erreur", e.getMessage());
} catch (InterruptedException e) {
MessageDialog.openInformation(shell, "Interruption", e.getMessage());
}
}
});
return composite;
}
public static void main(String[] args) {
new TestJFace5().run();
}
}
La suite de ce chapitre sera développée dans une version future de ce document |