Ce support de cours s'intéresse à présenter la boîte à outils SWT : évolution des boîtes à outils pour Java, conteneurs, composants de type Control, agents de placement, gestion des événements, Graphical Context, co-habitation entre SWT et Swing, traitement synchrone et asynchrone (ThreadUI) et les boîtes de dialogue.
Développement de clients
riches : Plateforme Eclipse
Mickaël BARON - 2007 (Rév. Janvier 2009)
mailto:[email protected] ou mailto:[email protected]
mickael-baron.fr
mickaelbaron
(SWT) - Standard Widget Toolkit
Chapitre 2 : Boîtes à outils
2
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Creative Commons
Contrat Paternité
Partage des Conditions Initiales à l'Identique
2.0 France
http://creativecommons.org/licenses/by-sa/2.0/fr
Licence
3
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
3
À propos de l’auteur …
Mickaël BARON
Ingénieur de Recherche au LIAS
https://www.lias-lab.fr
Equipe : Ingénierie des Données et des Modèles
Responsable des plateformes logicielles, « coach » technique
Ancien responsable Java de Developpez.com (2011-2021)
Communauté Francophone dédiée au développement informatique
https://java.developpez.com
4 millions de visiteurs uniques et 12 millions de pages vues par mois
750 00 membres, 2000 forums et jusqu'à 5000 messages par jour
mickael-baron.fr
mickaelbaron
4
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Organisation du cours sur la boîte à outils SWT
Evolution des boîtes à outils pour Java
Conteneurs
Composants de type Control
Agents de placement
Gestion des événements
Dessiner avec Graphical Context
Les boîtes de dialogue (Message, Couleur, …)
Les indispensables (appel SWT dans des Threads …)
Co-habitation entre SWT et Swing
5
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Evolution des boîtes à outils Java
La bibliothèque AWT (Abstract Window Toolkit)
BAO historique de Java depuis le JDK 1.0 mais toujours utilisable
(souvent utilisée directement pour les Applets)
Tous les composants sont implémentés à partir du sous-ensemble
« portable » des composants natifs des systèmes hôtes (Heavyweight
Component)
L’affichage et le comportement de l’IHM sont fortement liés au
système hôte
Système graphique : X11, Windows, etc.
Peer
AWT
Application Java
Machine
virtuelle
Tracé graphique
Fournit un ensemble
d’interface permettant aux
composants graphiques
d’être représentés à l’écran
6
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Evolution des boîtes à outils Java
La bibliothèque Swing
BAO considérée comme standard en Java 2 Platform (depuis le JDK 2)
Tous les composants sont implémentés directement sans faire appel
aux composants natifs du système hôte (Lightweight Components)
L’affichage et le comportement de l’IHM sont indépendants du
système hôte et ne dépendent que du programmeur ou de l’utilisateur
(Look and Feel)
Système graphique : X11, Windows, etc.
Peer
AWT
Application Java
Machine
virtuelle Swing
Tracé graphique
7
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Boîte à outils SWT
SWT : Standard Widget Toolkit
Bibliothèque développée par IBM pour le projet Eclipse
www.eclipse.org/articles/Article-SWT-Design-1/SWT-Design-1.html
Distribuée librement pour le développement de plug-ins ou
d’application stand-alone
Fournit des composants de base (bouton, label, …)
Fournit des composants plus complexes avec JFace
Fournit un modèle pour la gestion des événements identique
à celui utilisé par AWT et Swing (abonnement)
8
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Boîte à outils SWT
Système graphique : X11, Windows, etc.
SWT.dll, SWT.so, …
SWT
Application Java
Machine
virtuelle
Tracé graphique
SWT fournit des techniques d’implémentation de bas niveau
SWT procure des composants graphiques natifs d’une
manière indépendante de l’OS
Combinaison de classes Java et JNI spécifiques à chaque plateforme
JNI utilisé pour invoquer le système d’exploitation
9
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Comparaison Swing/SWT
Performance : même si SWT s’appuie sur des composants
natifs il y a des cas particuliers où Swing est plus rapide
Affichage de très grand nombre d’information : JTable Swing plus
rapide qu’un TextViewer SWT/JFace
Composants natifs = meilleure réactivité et rapidité de chargement
Portabilité : avec SWT nécessité d’utiliser des bibliothèques
natives alors que pour Swing aucune contrainte
Pour SWT installation des bibliothèques
Pour Swing déjà pré-installé
10
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Comparaison Swing/SWT (suite)
Look : SWT ne permet pas de modifier l’apparence des
composants
Pour SWT respect des habitudes de l’utilisateur
Pour Swing possibilité de s’adapter à un type d’utilisateur (un look
cartoon pour les enfants)
Reproche à Swing son aspect non professionnel (à voir)
Développement : SWT nécessite de libérer les ressources
pas pour Swing
Pour SWT de nombreux composants adapté (assistant par exemple)
Swing n’est pas en reste avec les composants SwingLabs
Pour Swing plus de documentations pour l’aide au développement
Pour SWT moins d’exemples mais ça arrive …
11
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
SWT : les ressources …
Le site de la fondation Eclipse
La page d’accueil sur SWT (www.eclipse.org/swt)
Un ensemble d’exemples (www.eclipse.org/swt/snippets)
Des articles de la fondation Eclipse
www.eclipse.org/articles/Article-SWT-images/graphics-resources.html
www.eclipse.org/articles/Article-SWT-DND/DND-in-SWT.html
www.eclipse.org/articles/Article-SWT-Design-1/SWT-Design-1.html et 2
Et pleins d’autres encore …
Des supports de cours et des exemples
www.labo-sun.com/resource-fr-essentiels-903-0-java-gui-swt-creer-des-interfaces-
graphiques-performantes.htm
www.java2s.com/Code/Java/SWT-JFace-Eclipse/CatalogSWT-JFace-Eclipse.htm
12
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Principaux composants graphiques de SWT
Fenêtres
Les fenêtres de base et les boîtes de dialogue
Composants
Les principaux composants d’interaction : boutons, menus, Tree,
Table, Scale, …
Les composants JFace apporteront une vision MVC des composants
Conteneurs
Composants spécifiques (parfois invisibles) qui servent à contenir
des composants et/ou Conteneurs
Les fenêtres sont des conteneurs
Agents de placements
Ce sont des objets qui servent à placer des composants dans un
conteneur
13
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Exemple : le compteur file rouge
Le compteur …
Un bouton et un entier sont affichés dans une fenêtre
Lorsque l’utilisateur appuie sur le bouton, l’entier est incrémenté d’une
unité puis affiché
Composants graphiques visibles
Une fenêtre principale
Un bouton que l’utilisateur peut déclencher
Une zone de texte non modifiable par l’utilisateur
Réaction aux actions de l’utilisateur
L’événement « clic sur le bouton » doit incrémenter l’entier et
l’afficher à nouveau
Fenêtre
Bouton
Label
14
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Le compteur : structure des composants
La fenêtre
Classe : Shell
Le contenu de la fenêtre
La fenêtre est un conteneur de type Composite
Permet d’y ajouter les autres composants
Le bouton et la zone de texte
Classes : Button et Label
Ajoutés au conteneur pour pouvoir s’y afficher
Le placement des composants
n’est pas encore défini
myShell
Shell
Composite
myLabel
myButton
…
Détail plus tard …
myShell
contient
15
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Le compteur : implémentation
Étapes de développement
Récupération du Display
Création de la fenêtre
Création des composants
en les ajoutant à la fenêtre
Dimensionnement de la
fenêtre (optionnel)
Affichage de la fenêtre
public class Compteur {
public Compteur() {
Display display = new Display();
Shell myShell = new Shell(display);
myShell.setText("Compteur");
Button myButton = new Button(myShell,SWT.NONE);
myButton.setText("i->i+1");
Label myLabel = new Label(myShell, SWT.CENTER);
myLabel.setText("i = 0");
myShell.pack();
myShell.open();
while(!myShell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
public static void main (String args[]) {
new Compteur();
}
}
Détail plus tard …
Compteur.java du projet
IntroExamples
16
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Le compteur : résultat de l’affichage …
Le résultat n’est pas celui espéré …
Le placement des composants n’a pas été effectué
Les composants ne sont pas visibles (ils le sont mais leur position et
leur taille sont nulles)
Il manque un agent de placement de type Layout
Par défaut il n’y a pas d’agent de placement (null)
17
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Placement d’un composant dans un conteneur
Une IHM en Java peut avoir plusieurs apparences
La taille et le type de police varient
Les composants possèdent différentes représentations
Le placement des composants ne peut se faire de manière absolue
Utilisation d’agents de placement : « Layout Manager »
Un agent de placement est associé à un conteneur
Par défaut il n’y a pas d’agent de placement (null) qui est utilisé dans
les conteneurs
L’agent de placement place les composants les uns par rapport aux
autres
de la taille préférée de chacun des composants
de la place disponible dans le conteneur
de la politique de placement définie par l’agent de placement
18
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Le compteur : utilisation d’un RowLayout
public class CompteurLayout {
public CompteurLayout() {
Display display = new Display();
Shell myShell = new Shell(display);
myShell.setText("Compteur");
myShell.setLayout(new RowLayout(SWT.VERTICAL));
Button myButton = new Button(myShell,SWT.NONE);
myButton.setText("i->i+1");
Label myLabel = new Label(myShell, SWT.CENTER);
myLabel.setText("i = 0");
myShell.pack();
myShell.open();
...
}
public static void main (String args[]) {
new CompteurLayout();
}
}
Les composants sont placés par le RowLayout
en respectant leur taille préférée
de haut en bas
la méthode pack() demande le placement automatique des composants
Exemple : le compteur agencé avec RowLayout
Le placement est
correcte, il faudrait
par contre agrandir
la taille du bouton
en fonction de la
fenêtre
CompteurLayout.java du
projet IntroExamples
19
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
public class CompteurLayout2 {
public CompteurLayout2() {
Display display = new Display();
Shell myShell = new Shell(display);
myShell.setText("Compteur");
myShell.setLayout(new FillLayout(SWT.VERTICAL));
Button myButton = new Button(myShell,SWT.NONE);
myButton.setText("i->i+1");
Label myLabel = new Label(myShell, SWT.CENTER);
myLabel.setText("i = 0");
myShell.pack();
myShell.open();
while(!myShell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
public static void main (String args[]) {
new CompteurLayout2();
}
}
Le compteur : utilisation d’un FillLayout
Les composants sont placés par le FillLayout
de haut en bas (identique au RowLayout sans respect de la taille)
tous les éléments ont la même ligne
Exemple : le compteur agencé avec FillLayout
CompteurLayout2.java du
projet IntroExamples
20
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Réalisation classique d’une interface graphique
Étapes de la réalisation sans gestion des événements
Création d’une fenêtre avec un objet de type Shell
Création d’un agent de placement et association au conteneur du Shell
Création d’un composant
Ajout du composant au conteneur
Création d’un autre composant
…
Utilisez le plus possible des
conteneurs pour placer
correctement vos
composants. C’est gratuit …
21
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Conception d’une interface graphique complexe
Hiérarchisation des composants en arbre de conteneurs
Grouper les composants dans les conteneurs (Composite) avec une
politique de placement grâce aux agents de placement
Grouper de nouveaux les composants obtenus
Ces composants peuvent être
définis localement ou bien être
des instances d’autres classes
qui hériteraient de Composite
22
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Conception d’une interface graphique complexe
Décomposition des composants de l’application
Button(SWT.PUSH)
valider
Composite haut
(RowLayout)
Text (SWT.MULTI)
myText
Shell
(GridLayout)
Button(SWT.PUSH)
annuler
Button
(SWT.RADIO) sms
Button
(SWT.RADIO) email
Composite bas
(FillLayout)
bas
haut
myText
23
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Exemple : création d’un composant avec du texte un champ
Création du texte avec la classe Label
Création du champ avec la classe Text
Placement dans un Composite
Nouvelle classe LabelText hérite de Composite et pourra ainsi
être utilisée comme composant dans une autre application
Des composants réutilisables
public class CompositeWidgets extends Composite {
public CompositeWidgets(Composite parent, String label,
String textf) {
super(parent, SWT.NONE);
GridLayout myGL = new GridLayout(2, false);
this.setLayout(myGL);
Label myLabel = new Label(this, SWT.NONE);
myLabel.setText(label);
Text myText = new Text(this,SWT.BORDER);
myText.setText(textf);
GridData myGD = new GridData(GridData.FILL_BOTH);
myText.setLayoutData(myGD);
}
... // Suite dans le prochain transparent
}
CompositeWidgets.java du
projet IntroExamples
24
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Des composants réutilisables
Exemple (suite) : création d’un composant personnalisé
Création d’une fenêtre Shell
Création d’une instance du LabelText et ajout au container de la Shell
public class CompositeWidgets extends Composite {
... // Suite dans le précédent transparent
public static void main(String[] argv) {
Display display = new Display ();
Shell shell = new Shell (display);
shell.setLayout(new FillLayout(SWT.VERTICAL));
new LabelText(shell, "Saisissez le nom", "");
shell.pack ();
shell.open ();
while (!shell.isDisposed ()) {
if (!display.readAndDispatch ()) display.sleep ();
}
display.dispose ();
}
}
CompositeWidgets.java du
projet IntroExamples
25
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Des concepts de base
SWT utilise des ressources du système d’exploitation
Toutes ressources allouées se doivent d’être libérées
www.eclipse.org/articles/Article-SWT-Design-1/SWT-Design-1.html
Le garbage collector n’est pas capable de libérer la mémoire
puisqu’il lui est impossible de connaître l’ordre de libération
Règle 1 : « if you created it, you dispose it »
Libération explicite des ressources graphiques
Nécessité de libérer les ressources par la méthode dispose()
Font font = new Font (display, "Courier", 10, SWT.NORMAL);
... // Utilisation de l’objet fond
font.dispose();
Détruire les
objets
Font font = ref.getFont();
... // Utilisation de l’objet fond
Ne pas détruire les
objets
Récupération
d’un objet
Création d’un
objet
26
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Des concepts de base
Règle 2 : « disposing the parent, dispose the children »
Un composant ne peut pas exister dans le système d’exploitation sans
composant parent
Création du conteneur obligatoirement avec le contenu
Contrôle du cycle de vie via la relation parent-enfant exprimée via le
constructeur
Si le composant parent est libéré, les composants enfants seront
automatiquement libérés
public class Compteur {
public Compteur() {
Display display = new Display();
Shell myShell = new Shell(display);
myShell.setText("Compteur");
Button myButton = new Button(myShell,SWT.NONE);
...
}
...
}
A la construction des
composants, obligation
d’indiquer le conteneur
Les composants non
graphiques Font, Color, …
ne sont pas des enfants et
devront être libérés …
Si myShell libéré tous ces
enfants le sont aussi
27
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Le Display
Rôle et caractéristiques de la classe Display
Effectue la connexion entre l’application Java et le système
d’exploitation hôte
Fournit le mécanisme de traitement des événements
Package : org.eclipse.swt.widgets.Display
Quelques méthodes utiles de la classe Display
static Display getCurrent() ou getDefault() : récupère un Display
Rectangle getBounds() : récupère la taille de l’écran
Color getSystemColor(String id) : effectue la relation entre les couleurs
de SWT et du système
boolean readAndDispatch() : transfert les événements du système à
l’application, retourne vraie s’il y a encore des événements
setCursorLocation(int x, int y) : déplace le pointeur de l’écran
28
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Le Display
La fonction principale de l’objet Display est la gestion de la
boucle principale d’événements
En comparaison avec la boite à outils Swing où la boucle est
implicite, SWT nécessite de définir explicitement une boucle
Définition d’une boucle d’événement
public class Compteur {
public Compteur() {
...
while(!myShell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
}
readAndDispatch() récupère
les événements du système
hôte et les transmet à
l’application
Tant que la fenêtre
en « vie »
readAndDispatch
continue à
dispatcher
Si readAndDispatch()
retourne vraie des
événements sont encore à
traiter
Si readAndDispatch()
retourne faux mise en
attente jusqu’à l’arrivée de
nouveaux événements
29
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Erreurs et Exceptions
SWT distingue trois types d’exceptions
SWTError
Levée lors d’une erreur fatale
Une erreur irrécupérable
SWTException
Levée lors d’une erreur non fatale
Une erreur récupérable
Exemple : Invalid thread access
IllegalArgumentException
Exception levée lors d’une erreur non fatale
Un argument fourni est invalide
Exemple : argument ne peut être null
30
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
La hiérarchie des packages SWT
org.eclipse.swt : package de base qui contient la définition des
constantes (SWT) et des exceptions
org.eclipse.swt.accessibility : package concernant l’accessibilité
org.eclipse.swt.awt : package permettant l’intégration de
composants Swing dans SWT
org.eclipse.swt.browser : package concernant le composant browser
org.eclipse.swt.custom : composants particuliers (TableTree)
org.eclipse.swt.dnd : support du Drag&Drop
org.eclipse.swt.events : pour la gestion des événements
31
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
La hiérarchie des packages SWT
org.clipse.swt.graphics : ensemble de classes pour le graphique
org.eclipse.swt.layout : agents de placement
org.eclipse.swt.ole.win32 : gestion OLE pour Windows
org.eclipse.swt.printing : pour la gestion de l’impression
org.eclipse.swt.program : exécution d’application sur l’OS
org.eclipse.swt.widgets : API des composants graphiques
Dans la suite de ce cours nous
allons nous intéresser plus
particulièrement aux packages
widgets, graphics, events,
layout et awt
32
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
La hiérarchie des composants SWT
Hiérarchie des principaux composants
Control
Widget
Tray
Scrollable
Composite
Menu …
Button Label …
Combo Browser …
Text List Les sous-classes de
Control, Scrollable et
Composite seront
étudiées dans ce cours
33
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
La hiérarchie des composants SWT
La classe Widget est la classe de plus haut niveau pour les
composants graphiques
Sous-classes de Control
Service : composants fils à une fenêtre avec réaction à enregistrement
à des événements de base (MouseListener, KeyListener, …)
Exemples : Button, Label
Sous-classes de Scrollable
Service : composants avec des barres de défilement
Exemple : List, Text
Sous-classes de Composite
Service : composants capable de contenir des composants Control
appelés également conteneur
Exemple : Canvas, Group
34
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
La classe Widget
La classe Widget est la classe de plus haut niveau de la
hiérarchie SWT
Services proposés
Mécanisme générique de bas niveau pour la gestion des événements
Sémantique de construction et de destruction
Mécanisme de stockage d’information
Méthodes usuelles
void dispose() : libérer les ressources d’un composant
Display getDisplay() : récupère le Display associé au composant
addListener(int, Listener) : mécanisme d’abonnement
…
Cette classe ne peut être étendue pour le développement
35
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
La classe Control
La classe Control dérive de la classe Widget et chaque objet
Control encapsule un composant graphique natif : un peer
Tous les composants SWT à l’exception de ScrollBar et
Menu sont des Control
La classe Control fournit des méthodes pour contrôler
l’affichage et le comportement
Taille, couleur, police, menu popup, …
Abonnement aux écouteurs (listeners typés)
De nombreuses méthodes … se référer à l’API
36
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Galerie des composants : conteneurs
Shell
Composite
CoolBar
ToolBar
Combo
Spinner
Canvas
Browser
37
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Galerie des composants : conteneurs (suite)
Tree
Table
StyledText
CTabFolder
ExpandBar
Group
TabFolder
ScrolledComposite
38
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Galerie des composants : contrôle
Button (SWT.ARROW)
Button (SWT.PUSH) Button (SWT.CHECK)
Button (SWT.TOGGLE)
Button (SWT.RADIO)
Link
Label
39
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Galerie des composants : contrôle (suite)
Slider
Scale
Text (SWT.SINGLE)
Text (SWT.MULTI)
Sash
List
40
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Galerie des composants : les autres
Menu
Tray System
41
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les conteneurs de SWT : Shell
Shell permet la création d’une fenêtre (équivalent à la
JFrame de Swing)
Fenêtre indépendante dont l’apparence peut varier en
fonction du style donné lors de la construction
Possibilité de créer des sous fenêtres associées une fenêtre
parent
Construction
Shell(Display) : construit un Shell (style défaut) associé à un Display
Shell(Display, int) : avec un style défini
Shell(Shell) : construit un Shell associé à un Shell parent
Méthodes utiles
setVisible(boolean) : rend visible ou pas la fenêtre
open() : appel un ensemble de fonctionnalités (visible, active, …)
42
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les conteneurs de SWT : Shell
Les styles d’une fenêtre (constantes de la classe SWT)
BORDER : ajoute un border
CLOSE : ajoute un bouton de fermeture
MIN : ajoute un bouton pour minimiser la fenêtre
MAX : ajoute un bouton pour maximiser la fenêtre
RESIZE : ajoute un border pour le redimensionnement
TITLE : ajoute une barre de menu
Paramètres pré-définis
NO_TRIM : fenêtre sans possibilité de redimensionner, agrandir,
minimiser, déplaçable, border, …
DIALOG_TRIM : TITLE | CLOSE | BORDER
SHELL_TRIM : CLOSE | TITLE | MIN | MAX | RESIZE
43
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les fenêtres modales
SYSTEM_MODAL : modale au système complet (peu répandu)
APPLICATION_MODAL : création d’une fenêtre modale à l’application
PRIMARY_MODAL : création d’une fenêtre modale
MODE_LESS : non modale
Les conteneurs de SWT : Shell
NO_TRIM
DIALOG_TRIM
SHELL_TRIM
44
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les conteneurs de SWT : Composite
La classe Composite s’occupe de la gestion des conteneurs
Elle peut contenir des composants Control et par conséquent
d’autres objets de type Composite
Un objet Composite doit être rattaché directement à un objet
Shell, ou indirectement via d’autres conteneurs
Les composants sont ajoutés au conteneur au moment de la
construction des composants (En Swing les composants sont
ajoutés par l’intermédiaire de la méthode add du conteneur)
45
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les conteneurs de SWT : Composite
Un conteneur gère l’agencement des composants par un
agent de placement
Différentes méthodes utiles
Composite(Composite, int) : constructeur d’un Composite
layout(boolean) : active ou pas l’agencement
setLayout(Layout) : modifie l’agent de placement
Control[] getChildren() : retourne le nombre de Control contenu
setFocus() : affecte le focus au conteneur
La classe Shell étudiée
précédemment est du
type Composite
46
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les conteneurs de SWT : Group
Le conteneur Group est similaire à la classe Composite, il
impose une délimitation et permet d’ajouter un titre
En Swing, il s’agit d’un JPanel décoré d’un TitledBorder
Différentes méthodes utiles
setText(String p) : modifie le titre du Group
String getText() : récupère le titre du Group
Exemple : des composites décorés
Group temp = new Group(sShell, SWT.NONE);
temp.setText("Action");
temp.setLayout(new FillLayout(SWT.HORIZONTAL));
Button myButton = new Button(temp, SWT.NONE);
myButton.setText("i -> i + 1");
temp = new Group(sShell, SWT.NONE);
temp.setText("Résultat");
temp.setLayout(new FillLayout(SWT.HORIZONTAL));
Label myLabel = new Label(temp,SWT.CENTER);
myLabel.setText("i = " + i); }
47
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les conteneurs de SWT : ToolBar
ToolBar permet d’ajouter une barre d’outils en contenant un
ensemble de composants prédéfinis (Button, Toggle, …)
Une ToolBar peut être horizontale ou verticale
Chaque élément d’une barre d’outil est défini par un
ToolItem
Apparence d’un ToolItem (constantes de la classe SWT)
CHECK : un bouton de sélection (Toggle)
DROP_DOWN : un bouton avec un chevron
PUSH : un bouton classique
RADIO : un bouton de type radio (singleton sur la sélection)
SEPARATOR : un séparateur
ToolBar toolBar = new ToolBar(shell, SWT.HORIZONTAL)
Ou
ToolBar toolBar = new ToolBar(shell, SWT.VERTICAL)
48
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les conteneurs de SWT : ToolBar
Différentes méthodes pour ToolItem
setControl(Control) : modifie le contrôle quand l’item est un séparator
setSelection(boolean) : sélectionne ou pas
setEnabled(boolean) : active ou désactive
setText(String) : modifie le texte
setToolTipText(String) : modifie la bulle d’aide
setWidth(int) : modifie la taille en pixel de l’élément
Utilisation de la méthode setControl(Control)
Possibilité d’ajouter des composants Control à la ToolBar
Nécessite que le style du ToolItem soit SEPARATOR
49
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les conteneurs de SWT : ToolBar
Exemple : une barre d’outils …
public class ToolBarExample {
public ToolBarExample() {
Display display = new Display ();
Shell shell = new Shell (display);
ToolBar bar = new ToolBar (shell, SWT.HORIZONTAL);
ToolItem item = new ToolItem (bar, SWT.PUSH);
item.setText("Item 1");
Button myButton = new Button(bar,SWT.NONE);
myButton.setText("Ici");
item = new ToolItem(bar,SWT.SEPARATOR);
myButton.pack();
item.setWidth(myButton.getSize().x);
item.setControl(myButton);
bar.pack ();
shell.pack ();
shell.open ();
while (!shell.isDisposed ()) {
if (!display.readAndDispatch ()) display.sleep ();
}
display.dispose ();
...
}
Ajout d’un objet Control dans
la barre de menu
ToolBarExample.java du
projet IntroExamples
50
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les conteneurs de SWT : CoolBar
La CoolBar fonctionne sur le même principe que la ToolBar à
la différence où les éléments sont flotants
Pour interdire le déplacement d’éléments dans une CoolBar
utiliser la méthode setLocked(boolean)
Les éléments contenus dans une CoolBar sont définis par des
CoolItem
Element déplaçable
Element déplaçable
51
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les composants de contrôle : Button
La classe Button représente un bouton cliquable
A la différence de Swing où chaque type de bouton à une
classe prédéfinie (JButton, JRadioButton, JCheckBox, …) le
SWT se base sur les styles
Différentes méthodes utiles
setText(String) : modifie le texte du bouton
setSelection(boolean) : modifie la sélection
Différentes apparences (constantes de la classe SWT)
PUSH ou NONE : bouton par défaut
CHECK : case à cocher
RADIO : bouton radio
TOGGLE : bouton de sélection
ARROW : bouton avec flèche
52
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les composants de contrôle : Button
Exemple : un ensemble de boutons
public class ButtonsExample {
public ButtonsExample() {
Display display = new Display ();
Shell shell = new Shell (display);
shell.setText("Buttons Example");
shell.setLayout(new FillLayout(SWT.VERTICAL));
Button myButton = new Button(shell,SWT.PUSH);
myButton.setText("Push Me");
myButton = new Button(shell,SWT.CHECK);
myButton.setText("Check Me");
myButton = new Button(shell,SWT.RADIO);
myButton.setText("Radio Me");
myButton = new Button(shell,SWT.RADIO);
myButton.setText("Radio Me");
myButton = new Button(shell,SWT.TOGGLE);
myButton.setText("Select Me");
myButton = new Button(shell,SWT.ARROW);
myButton.setText("Turn Me");
...
}
Les boutons de type RADIO sont
groupés s’ils appartiennent au
même Composite
ButtonsExample.java du
projet IntroExamples
53
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les composants de contrôle : Label et Text
La classe Label permet d’afficher un texte ou une image
setText(String) : modifie le texte
setImage(Image) : modifie l’image
La classe Text est une zone de texte contenant une ou
plusieurs ligne (SINGLE ou MULTI)
setText(String) : modifie le texte
setTextLimit(int) : définit la limite de la chaîne
setEditable(boolean) : précise si la zone de texte est éditable
Exemple : un ensemble de textes
public class LabelTextExample {
public LabelTextExample() {
Display display = new Display ();
Shell shell = new Shell (display);
shell.setText("Buttons Example");
shell.setLayout(new FillLayout(SWT.VERTICAL));
Label myLabel = new Label(shell, SWT.BORDER);
myLabel.setText("Message");
Text myText = new Text(shell, SWT.BORDER | SWT.MULTI);
myText.setText("Coucou");
...
}
LabelTextExample.java du
projet IntroExamples
54
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
L’art de placer les composants SWT
Les agents de placement ou Layout Manager
FillLayout
RowLayout
FormLayout
GridLayout StackLayout
55
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les agents de placement et les composants
Les agents de placement permettent d’agencer les widgets
contenus dans un objet Composite
Un agent de placement hérite de classe Layout
Il peut s’agir de composants de type Control ou Composite
L’agent de placement est associé à un objet Composite
setLayout(Layout) : modification d’un agent de placement
Chaque widget peut influencer son comportement dans son
conteneur par la méthode
setLayoutData(Object) : objet spécifique suivant le type d’agent de
placement
Pour appliquer l’agencement et le re-dimensionnement des
objets Control, utiliser la méthode pack()
56
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les agents de placement : FillLayout
Affiche horizontalement ou verticalement les composants les
uns à la suite des autres
VERTICAL ou HORIZONTAL constantes de la classe SWT
Tous les composants sont redimensionnés de manière
identique, ne conserve donc pas la taille des composants
Dés que le conteneur est redimensionné les composants se
distribuent l’espace
Exemple : boutons alignés verticalement
sShell.setLayout(new FillLayout(SWT.VERTICAL));
Button myButton = new Button(sShell, SWT.NONE);
myButton.setText("Bouton 1");
myButton = new Button(sShell, SWT.NONE);
myButton.setText("Bouton 2");
myButton = new Button(sShell, SWT.NONE);
myButton.setText("Bouton 3");
myButton = new Button(sShell, SWT.NONE);
myButton.setText("Bouton 4");
FillLayout.java du projet
LayoutExamples
57
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les agents de placement : RowLayout
Affiche horizontalement ou verticalement les composants les
uns à la suite des autres (si possible)
VERTICAL ou HORIZONTAL constantes de la classe SWT
Possibilité de conserver la taille des composants
Si pas assez de place débordement sur une nouvelle ligne ou
une colonne
Peut être comparé à l’agent de placement FlowLayout de
Swing (mais en plus expressif)
Possibilité de contraindre chaque composant par un objet de
type RowData
RowData(int width, int height) : largeur et hauteur
58
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les agents de placement : RowLayout
RowLayout peut être paramétré après sa construction
boolean justify : précise si les composants doivent être justifiés
int marginBottom, marginTop : marge du bas et du haut
int marginLeft, marginRight : marge à gauche et à droite
boolean pack : si true les composants gardent leur taille préférée
int spacing : espace entre les contrôles
int type : orientation (SWT.VERTICAL ou SWT.HORIZONTAL)
boolean wrap : si true retour à la ligne quand plus de place
59
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les agents de placement : RowLayout
RowLayout myLayout = new RowLayout(SWT.HORIZONTAL);
myLayout.wrap = true;
sShell.setLayout(myLayout);
Button myButton = new Button(sShell, SWT.NONE);
myButton.setText("Bouton 1");
myButton = new Button(sShell, SWT.NONE);
myButton.setText("Bouton 2");
myButton = new Button(sShell, SWT.NONE);
myButton.setText("Bouton 3");
myButton = new Button(sShell, SWT.NONE);
myButton.setText("Bouton 4");
myButton.setLayoutData(new RowData(100,100));
Exemple : un ensemble de boutons
Le dernier bouton
est agrandi
Différents
résultats en
fonction de la
taille de la
fenêtre
RowLayoutExample.java du
projet LayoutExamples
60
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les agents de placement : GridLayout
L’agent de placement GridLayout est un des plus expressif et
pourrait être suffisant
Il contrôle une grille avec la possibilité de fusionner des
cellules et de contraindre ou pas la largeur des cellules
Comparable au GridLayout de Swing en plus expressif
Construction d’un GridLayout
GridLayout(int nc, boolean ew) : construit un GridLayout avec nc
nombre de colonnes. Si ew = true les colonnes ont la même taille
GridLayout() : construit un GridLayout avec une colonne et les
colonnes n’auront pas la même taille
61
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les agents de placement : GridLayout
GridLayout peut être paramétré après sa construction
int horizontalSpacing : espace horizontal entre les cellules
int verticalSpacing : espace vertical entre les cellules
boolean makeColumnsEqualWidth : true = force toutes les colonnes à
avoir la même taille
int marginHeight, marginWidth : marge en largeur et en hauteur
int numColumns : nombre de colonne
Possibilité de contraindre chaque composant par un objet de
type GridData
GridData(int style) : construit un GridData avec un style spécifié
62
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les agents de placement : GridLayout
GridData peut être paramétré après sa construction
int horizontalSpan : le nombre de colonne occupé
int verticalSpan : le nombre de ligne occupé
int horizontalAlignment : précise le type d’alignement GridData.FILL,
.BEGINNING, .CENTER et .END
boolean grabExcessHorizontalSpace : si TRUE force la cellule à remplir
l’espace disponible
…
Les différentes constantes utilisables
FILL_BOTH : rempli l’espace disponible horizontal et vertical
FILL_HORIZONTAL : rempli l’espace disponible horizontal
FILL_VERTICAL : rempli l’espace disponible vertical
…
FILL, BEGINNING,
CENTER et END ne sont
pas utilisables pour
construire un GridData
63
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les agents de placement : GridLayout
Exemple : un ensemble de boutons
GridLayout myLayout = new GridLayout(3, false);
sShell.setLayout(myLayout);
Button myButton = new Button(sShell, SWT.NONE);
myButton.setText("Bouton 1");
myButton = new Button(sShell, SWT.NONE);
myButton.setText("Bouton 2");
myButton = new Button(sShell, SWT.NONE);
myButton.setText("Bouton 3");
myButton = new Button(sShell, SWT.NONE);
myButton.setText("Bouton 4");
GridData myData = new GridData(GridData.FILL_BOTH);
myData.horizontalSpan = 3;
myButton.setLayoutData(myData);
Trois cellules en haut
Trois cellules
fusionnées
GridLayoutExample.java du
projet LayoutExamples
64
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les agents de placement : FormLayout
L’agent de placement FormLayout organise les Control en
exploitant des contraintes de placement
Comparable au GridBagLayout de Swing
Possibilité de contraindre chaque composant par un objet de
type FormData
Utilisation d’un objet additionnel FormAttachment lié au
FormData pour contrôler la taille et le placement
Attributs d’un FormData
int height, width : hauteur et largeur pour le Control
FormAttachment bottom, left, right, top : la contrainte pour le bas, la
gauche, la droite et le haut du Control
65
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les agents de placement : FormLayout
FormAttachment définit comment les composants sont
positionnés entre eux
Cet objet permet de définir l’alignement et la taille d’un
Control
Un FormAttachment peut être associé à un Control pour
définir ainsi des contraintes entre objets Control
Représentation mathématique de l’objet FormAttachment
sous la forme d’une équation de type : y = a x + b
y = coordonnées après attachement
x = coordonnées avant attachement
a = pourcentage de l’objet attaché ( a = numérateur / dénominateur)
b = offset
66
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les agents de placement : FormLayout
Attributs d’un FormAttachment
int alignment : côté du Control avec lequel le FormAttachment sera
attaché SWT.TOP, .CENTER, .BOTTOM, .LEFT, .RIGHT
Control control : l’objet Control associé au FormAttachment
int denominateur : dénominateur de a (défaut : 100)
int numerator : numérateur de a
int offset : décalage
Construction d’un FormAttachment
FormAttachment(Control p, int offset)
FormAttachment(int numerator, int offset)
FormAttachment(int numerator, int denominateur, int offset)
…
67
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les agents de placement : FormLayout
Exemple (EP 1) : FormLayout sans FormAttachment
FormLayout formLayout = new FormLayout();
shell.setLayout(formLayout);
FormData formData = new FormData();
formData.height = 120;
formData.width = 120;
Button button = new Button(shell, SWT.PUSH);
button.setLayoutData(formData);
button.setText("Button 1");
Le bouton conserve sa
taille préférée lors de
l’agrandissement de
son container
FormLayoutExample1.java
du projet LayoutExamples
68
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les agents de placement : FormLayout
Exemple (EP 2) : FormLayout avec FormAttachment
FormLayout formLayout = new FormLayout();
shell.setLayout(formLayout);
FormData formData = new FormData();
formData.height = 120;
formData.width = 120;
formData.left = new FormAttachment(0,20);
formData.right = new FormAttachment(100,-20);
formData.top = new FormAttachment(0,20);
formData.bottom = new FormAttachment(100,-20);
Button button = new Button(shell, SWT.PUSH);
button.setLayoutData(formData);
button.setText("Button 1");
Fixé à 20 pixels à gauche
Fixé à 20 pixels à droite
Fixé à 20 pixels en haut
Fixé à 20 pixels en bas
Le bouton est
collé au partie
droite et basse
FormLayoutExample2.java
du projet LayoutExamples
69
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les agents de placement : FormLayout
Exemple (EP 2) bis : FormLayout avec FormAttachment
Côté droit
y = (100 / 100) x - 20
Côté gauche
y = (0 / 100) x + 20
A chaque re-dimensionnement du
conteneur la position du côté
droit du bouton varie linéairement
A chaque re-dimensionnement du
conteneur la position du côté
gauche du bouton ne change pas
x (coordonnées
avant attachement)
x (coordonnées
après attachement)
70
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les agents de placement : FormLayout
Exemple (EP 2) bis : FormLayout avec FormAttachment
Numérateur = 0, offset > 0
Numérateur = 100, offset < 0
Numérateur = 0,
offset > 0
Numérateur = 100,
offset > 0
Valeurs pour les cas généraux du
moment que les FormAttachment
ne sont pas liés à un Control
71
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les agents de placement : FormLayout
Exemple (EP 3) : FormLayout avec FormAttachment et
Control associé FormLayout formLayout = new FormLayout();
shell.setLayout(formLayout);
Button button1 = new Button(shell, SWT.PUSH);
button1.setText("Button 1");
Button button2 = new Button(shell, SWT.PUSH);
button2.setText("Button 2");
FormData formData = new FormData();
formData.left = new FormAttachment(0,20);
formData.right = new FormAttachment(100,-20);
formData.top = new FormAttachment(0,20);
formData.bottom = new FormAttachment(button2,0,SWT.TOP);
button1.setLayoutData(formData);
formData = new FormData();
formData.left = new FormAttachment(0,20);
formData.right = new FormAttachment(100,-20);
formData.bottom = new FormAttachment(100,-20);
formData.top = new FormAttachment(1,2,0);
button2.setLayoutData(formData);
Relier le bas de bouton1
avec le haut du bouton2
FormLayoutExample3.java du
projet LayoutExamples
72
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les agents de placement : StackLayout
L’agent de placement StackLayout permet d’empiler des
Control et de choisir celui qui sera visible
Similaire au CardLayout de Swing
Ne fait pas partie du package org.eclipse.swt.layout
StackLayout peut être paramétré après sa construction
int marginHeight : marge en hauteur
int marginWidth : marge en largeur
Control topControl : objet Control à afficher
Si l’objet topControl est null aucun objet Control ne sera
affiché
Pour changer d’objet Control à afficher
Modifier l’objet contenu dans topControl du StackLayout
Appeler layout() du Composite
73
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les agents de placement : StackLayout
Exemple : StackLayout et deux boutons
final Shell shell = new Shell (display);
final StackLayout stackLayout = new StackLayout();
shell.setLayout(stackLayout);
Button button1 = new Button(shell, SWT.PUSH);
button1.setText("Button 1");
final Button button2 = new Button(shell, SWT.PUSH);
button2.setText("Button 2");
button1.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent arg0) {
stackLayout.topControl = button2;
shell.redraw();
}
});
stackLayout.topControl = button1;
A la suite de l’action
sur button1, button2
devient l’objet Control
courant dans le
StackLayout
FormLayoutExample3.java
du projet
LayoutExamples
74
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les agents de placement : aucun …
Ne pas utiliser d’agent de placement vous impose pour
chaque composant de :
les positionner dans leur parent
définir la taille
L’absence d’agent de placement ne permet pas de produire
des interfaces qui s’adaptent au système
Pour préciser que vous ne voulez pas d’agent de placement
donner une valeur null à la méthode setLayout(…)
Dans quels cas ne pas utiliser d’agent de placement
Construction d’un GUI-Builder
75
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les agents de placement : aucun …
Exemple : sans agent de placement avec 2 boutons
Shell shell = new Shell (display);
shell.setLayout(null);
Button button = new Button(shell, SWT.PUSH);
button.setText("Button 1");
button.setBounds(0, 0, 125, 125);
button = new Button(shell, SWT.FLAT);
button.setText("Button 2");
button.setBounds(0, 125, 125, 125);
button = new Button(shell, SWT.FLAT);
button.setText("Button 3");
button.setBounds(0, 250, 125, 125);
Le LayoutManager du
Shell est null
Modification de la
position et de la taille
pour chaque
composant
StackLayoutExample.java du
projet LayoutExamples
76
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Conception et programmation
Affichage des informations vers l’utilisateur
Instanciation des composants de la BAO SWT
Mise en place des composants visibles grâce à des conteneurs et
agents de placement
Mais l’interface ne peut pas réagir aux actions de l’utilisateur
Clic sur le bouton
Terminaison de l’application
Réaction aux actions de l’utilisateur
En SWT, toute interaction est encapsulée dans un événement
Le traitement des interactions revient à récupérer et interpréter les
événements
SWT utilise le principe de l’abonnement
77
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Traitement des événements SWT
Chaque composant de l’interface graphique peut émettre des
événements
C’est une source (Widget)
Des objets peuvent recevoir ces événements
Ce sont des écouteurs (les listeners)
La liaison entre source et écouteur se fait par abonnement
On associe à une source un ou plusieurs écouteurs et réciproquement
SWT fournit deux types de listeners
Les listeners non typés (Listener)
Les listeners typés (EventListener)
Les événements sont définis par une classe Java qui dépend
du type de listener
Event pour les listeners non typés
TypedEvent pour les listeners typés
78
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Intérêt du traitement par abonnement
Exemple d’un compteur qui incrémente et décrémente
Deux boutons
« OUI » incrémente une variable
« NON » décrémente la même variable
Un son est émis à chaque pression sur un des boutons
Un bouton est associé deux fois à un même événement avec deux
actions différentes
+1 -1
Beep !
SelectionEvent
SelectionEvent SelectionEvent
79
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Intérêt du traitement par abonnement
En quoi consiste l’abonnement ?
Enregistrer (abonner) auprès de l’objet source un écouteur
Exemple :
Qu’est-ce qu’un écouteur ?
Une classe (même anonyme) qui implémente une interface (au sens
Java du terme)
monBouton.addListener(monListener);
Selon le type d’écouteur, la
méthode d’abonnement et la
classe de l’écouteur varient
80
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Traitement des événements : les listeners non typés
Les listeners non typés sont représentés par l’interface
Listener contenant une seule méthode
void handleEvent(Event event) : méthode de traitement d’un
événement
L’abonnement à cet écouteur non typé est effectué par la
méthode (présente dans la classe Widget)
void addListener(int eventType, Listener listener) : méthode réalisant
l’abonnement entre une source (Widget) et un objet de type Listener
pour le type d’événement défini par eventType
button.addListener(SWT.SELECTION, new Listener() {
public void handleEvent(Event e) {
switch(e.type) {
case SWT.SELECTION :
System.out.println("Button Pressed");
break;
}
}
}
button est
une source
Abonnement de
button avec un
listener pour
écouter un
événement
SELECTION
Traitement de
l’événement
81
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Traitement des événements : les listeners non typés
Le type d’événement à considérer au cours de l’abonnement
est défini par des constantes de type int stockées dans SWT
Activate : fenêtre active
Close : widget terminé
Collapse : un nœud d’arbre réduit
Deactivate : fenêtre non active
Dispose : composant détruit
Expand : un nœud d’arbre éclaté
FocusIn : widget gagne le focus
FocusOut : widget perd le focus
KeyDown : presse une touche clavier
KeyUp : relacher une touche clavier
MouseEnter : souris entre dans un widget
MouseExit : souris sort du widget
MouseHover : souris au dessus du widget
MouseMove : souris se déplace dans widget
MouseUp : bouton souris relaché
MouseDown : bouton souris pressé
MouseDoubleClick : pour le double click
Move : déplacement d’un widget
Paint : le widget est dessiné
Resize : widget rediemensionné
Selection : widget sélectionné
Show : widget affiché
…
82
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Traitement des événements : les listeners non typés
La classe Event permet de définir le contenu de l’événement
Elle contient des attributs qui caractérisent l’événement
Certains attributs sont dépendants du type d’événement
considéré
Par exemple pour l’événement de type MouseDoubleClick
int button : modélise le bouton de la souris : 1 pour le bouton de
gauche, 2 pour le second et 3 pour le troisième
int type : le type de l’événement considéré
int time : la date à laquelle l’événement a été provoquée
int x et y : position de la souris
Widget item : la source de l’événement
83
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Traitement des événements : les listeners non typés
Exemple : un bouton et des réactions
...
myButton.addListener(SWT.MouseDoubleClick, new Listener() {
public void handleEvent(Event event) {
System.out.println("Type de l'événement : " + event.type);
((Button)event.widget).setText("DoubleClick");
System.out.println("Date de déclenchement : " + event.time);
System.out.println("Position x et y : " + event.x + " / " + event.y);
System.out.println("Quel bouton ? : " + event.button);
}
});
...
InfoEventExample.java du
projet EventExamples
84
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Traitement des événements : les listeners typés
Les listeners typés sont représentés par un ensemble
d’interface stockés dans le package org.eclipse.swt.events
Les listeners typés fournissent en quelque sort une
encapsulation du type d’événement
Pour chaque famille d’événement un listener est proposé
MouseListener : écouteur adapté pour les événements de clicks de la
souris
Chaque listener propose un ensemble de méthodes associé à
un type précis d’événement
mouseDoubleClick(MouseEvent e) : pour le double click
mouseDown(MousEvent e) : quand le bouton est pressé
mouseUp(MouseEvent e) : quand le bouton est levé
85
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Traitement des événements : les listeners typés
86
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Traitement des événements : les listeners typés
87
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Programmation du traitement
Créer une source
Instancier un composant (e.g. un Button) pour l’affichage, c’est
automatiquement une source d’événements
Ne pas oublier de garder une référence disponible sur ce composant
Créer un écouteur
Implémenter dans une classe une des interfaces du package events
(e.g. un SelectionListener) selon le type d’événement écouté
Coder les effets de bord attendus dans une des méthodes de cette
classe (e.g. public void widgetSelected(SelectionEvent))
Instancier un objet de cette classe
Abonner l’écouteur à la source
Abonner l’instance de la source à l’instance de l’écouteur
88
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Créer le composant Button
Créer l’écouteur des SelectionEvent
Implémenter l’interface SelectionListener
Insérer les effets de bord dans la méthode
public void widgetSelected(SelectionEvent evt)
Abonner l’écouteur à l’objet émetteur d’événements
Utiliser la méthode d’abonnement proposée par le composant source
addSelectionListener(SelectionListener al)
Programmation du traitement : exemple
SelectionEvent
ControlEvent
KeyEvent
MouseEvent
…
Selection
Listener
89
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Programmation du traitement : exemple
Exemple : un bouton abonné à un SelectionListener
public class CompteurWithEvent {
private int i = 0;
private Label myLabel;
public CompteurWithEvent() {
Display display = new Display();
Shell myShell = new Shell(display);
myShell.setText("Compteur");
myShell.setLayout(new FillLayout(SWT.VERTICAL));
Button myButton = new Button(myShell,SWT.NONE);
myButton.addSelectionListener(new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent e) {
}
public void widgetSelected(SelectionEvent e) {
i++;
myLabel.setText("i = " + i);
}
});
myButton.setText("i->i+1");
myLabel = new Label(myShell, SWT.CENTER);
myLabel.setText("i = 0");
...
}
}
Méthode
implémentée
à vide car
pas utile
Nécessite
que myLabel
soit vu
comme
attribut de la
classe
CompteurWithEvent.java du
projet EventExamples
90
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Programmation du traitement : exemple
Exemple : une fenêtre qui ne se ferme pas …
public class CloseShellExample {
public CloseShellExample() {
Display display = new Display();
final Shell myShell = new Shell(display);
shell.setLayout(new FillLayout());
shell.setText("CloseShellExample");
shell.addShellListener(new ShellAdapter() {
public void shellClosed(ShellEvent event) {
event.doit = false;
}
});
Button myButton = new Button(shell, SWT.FLAT);
myButton.setText("Une fenêtre qui ne se ferme pas comme d'habitude");
myButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent arg0) {
shell.dispose();
}
});
...
}
}
Quand une fenêtre
est fermée, elle est
disposée.
Pour empêcher le dispose
Il faut cliquer sur le
bouton pour fermer la
fenêtre
CloseShellExample.java du
projet EventExamples
91
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Programmation du traitement : exemple
Certaines interfaces écouteur (Listener) ont une équivalence
adaptateur (Adapter)
Une classe adaptateur est une implémentation à vide d’un
écouteur
De façon générale s’il y a plus d’une méthode à implémenter
un adapter est obligatoirement fourni
En utilisant un adaptateur de l’héritage est effectuée et plus
précisément de la re-définition de méthodes
Inversement une interface nécessite une implémentation de
l’ensemble des méthodes
92
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Programmation du traitement : exemple
Exemple : un bouton abonné à un SelectionListener par
l’intermédiaire d’un adapter
public class CompteurWithEvent2 {
private int i = 0;
private Label myLabel;
public CompteurWithEvent2() {
Display display = new Display();
Shell myShell = new Shell(display);
myShell.setText("Compteur");
myShell.setLayout(new FillLayout(SWT.VERTICAL));
Button myButton = new Button(myShell,SWT.NONE);
myButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
i++;
myLabel.setText("i = " + i);
}
}
myButton.setText("i->i+1");
myLabel = new Label(myShell, SWT.CENTER);
myLabel.setText("i = 0");
...
}
}
Héritage de la classe
SelectionAdapter
Nécessite
que myLabel
soit vu
comme
attribut de la
classe
Faites attention lors de la
re-définition des méthodes
à ne pas vous tromper dans
leur signature
CompteurWithEvent2.java
du projet EventExamples
93
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Programmation du traitement : les recettes
Pour abonner un composant à un écouteur trois recettes sont
envisageables
Abonnement par un écouteur externe
Une classe externe s’occupe spécifiquement du fonctionnement de
l’écouteur
Abonnement par un écouteur interne
La classe où se trouve les sources (la partie graphique) sert également
d’écouteur
Abonnement par un écouteur locale
Pour chaque abonnement avec une source, utilisation d’une classe
anonyme « inner class »
Exemple : abonnement d’un bouton à MouseListener (cet
écouteur possède trois méthodes)
94
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Abonnement par un écouteur externe
La définition de l’écouteur se fait en dehors de la classe
Exemple
Il faut implémenter chacune des méthodes même s’il n’y a
rien à mettre dedans
Difficulté d’accéder aux attributs de la classe Exemple
public class Exemple {
...
public Exemple() {
...
myBut.addMouseListener(new EcouteurInterface());
}
}
public class EcouteurInterface implements MouseListener {
public void mouseDoubleClick(MouseEvent e) {
...
}
public void mouseDown(MouseEvent e) {
}
public void mouseUp(MouseEvent e) {
}
}
Cet écouteur est
utilisé par la classe
Exemple
95
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Abonnement par un écouteur externe : adapter
La définition de l’écouteur se fait en dehors de la classe
Exemple
Il faut redéfinir chacune des méthodes même s’il n’y a rien
à mettre dedans
Difficulté d’accéder aux attributs de la classe Exemple
public class EcouteurAdapter extends MouseAdapter {
public void mouseDoubleClick(MouseEvent e) {
...
}
public void mouseUp(MouseEvent e) {
...
}
}
public class Exemple {
...
public Exemple() {
...
myBut.addMouseListener(new EcouteurAdapter());
}
}
Cet écouteur est
utilisé par la classe
Exemple
Redéfinition uniquement
des méthodes nécessaires
96
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Abonnement par un écouteur interne
public class Exemple implements MouseListener {
...
public Exemple() {
...
myBut.addMouseListener(this);
}
public void mouseDoubleClick(MouseEvent e) {
this.myBut...
}
public void mouseDown(MouseEvent e) {
}
public void mouseUp(MouseEvent e) {
}
}
La définition de l’écouteur se fait dans la classe Exemple par
implémentation
Il faut implémenter chacune des méthodes même s’il n’y a
rien à mettre dedans
Possibilité d’accéder facilement aux attributs de la classe
Exemple
Accès aux
attributs de la
classe
Implémentation à
vide
97
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Abonnement par un écouteur locale : interface
La définition de l’écouteur se fait dans une « inner classe »
par implémentation et localement à la classe Exemple
Il faut implémenter toutes les méthodes même s’il n’y a rien
dedans
Possibilité d’accéder facilement aux attributs de la classe
Exemple public class Exemple {
...
public Exemple() {
...
myBut.addMouseListener(new MouseListener() {
public void mouseDoubleClick(MouseEvent e) {
Exemple.this.myBut...
}
public void mouseDown(MouseEvent e) {
}
public void mouseUp(MouseEvent e) {
}
});
}
}
Implémentation
à vide
Accès aux
attributs de
la classe
98
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Abonnement par un écouteur locale : adapter
public class Exemple {
...
public Exemple() {
...
myBut.addMouseListener(new MouseAdapter() {
public void mouseDoubleClick(MouseEvent e) {
Exemple.this.myBut...
}
});
}
}
La définition de l’écouteur se fait dans une « inner classe »
par dérivation et localement à la classe Exemple
Il faut redéfinir les méthodes dont on a besoin
Possibilité d’accéder facilement aux attributs de la classe
Exemple
Cette solution et la précédente sont à utiliser si le
traitement de l’écouteur est utilisé par une seule source
Ne vous trompez pas
dans la signature des
méthodes sinon
risque de définition
de nouvelles
méthodes
99
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Dessiner avec Graphical Context
Possibilité de dessiner en utilisant la classe GC (Graphical
Context) sur des Control, Image et Device
GC fournit un ensemble de méthodes pour dessiner des
formes, des textes et des images
Principe
Récupération ou création du GC
Traitement du dessin
Si le GC a été créé, libérer la ressource
Récupération du GC avec l’écouteur PaintListener
myComponent.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent event) {
event.gc.setBackground(...);
}
});
Le GC n’est pas créé mais
récupéré du Control
myComponent
100
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Dessiner avec Graphical Context
La construction d’un GC se fait par l’intermédiaire d’un objet
Drawable (Control, Device et Image)
L’objet Canvas est spécialement conçu pour le dessin
A la différence des autres objets Control, Canvas dessine un
rectangle plein d’une couleur par défaut
Possibilité de paramétrer le comportement du Canvas
SWT.NO_BACKGROUND : pas de couleur pour le fond
SWT.NO_REDRAW_SIZE : pas de dessin pour le re-dimensionnement
…
GC myGC = new GC(myControlComponent);
myGC.drawText(...);
myGC.drawLine(...);
...
myGC.dispose();
N’oubliez pas, si
vous créez vous
devez disposez !!!
101
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Dessiner avec Graphical Context : les couleurs
La couleur est définie par la classe Color
Color(Device d, RGB rgb)
Un objet RGB défini un triplet de trois composantes
RGB(int red, int green, int blue)
Possibilité de récupérer des couleurs définies par SWT par
l’intermédiaire de la classe Display
getSystemColor(int color) : constantes définies dans SWT
Des méthodes pour modifier la couleur du GC
setBackground(Color color) : Modification de la couleur de fond pour
les opérations de remplissage et pour le fond du texte
setForeground(Color color) : modification de la couleur de dessin et
pour la couleur d’écriture du texte
setAlpha(int alpha) : modification de l’opacité (alpha) de la couleur (0
transparent, 255 opaque)
102
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Dessiner avec Graphical Context : les couleurs
Exemple : création, récupération, utilisation et libération de
couleurs
...
myCanvas.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent event) {
Color myColor = new Color(Display.getDefault(), new RGB(200,212,123));
event.gc.setBackground(myColor);
event.gc.setAlpha(100);
event.gc.fillRectangle(0,0,200,200);
event.gc.setForeground(Display.getSystemColor(SWT.COLOR_BLUE));
event.gc.drawText("Message à afficher", 20, 20, true);
myColor.dispose();
}
}
...
Le texte sera affiché
sur fond transparent
L’objet Color myColor
doit être disposé
Récupéré donc ne
pas disposer
ColorGraphicContextExample.java
du projet GraphicExamples
103
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Dessiner avec Graphical Context : les formes
Dessine de points, lignes, poly-lignes, rectangles, polygones,
ellipses, arcs, …
drawXXX(…) : dessine une forme XXX
Dessine des formes pleines comme des rectangles, ellipses,
arcs, …
fillXXX(…) : dessine une forme pleine XXX
Modification des caractéristiques d’une ligne
setLineStyle(int style) : modification du style de la ligne
setLineWidth(int style) : modification de la taille de la ligne
Modification de la zone utilisée pour l’affichage (clipping)
setClipping(Rectangle p) : définition d’une zone par un Rectangle
(également un Path ou une Region)
104
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Dessiner avec Graphical Context : les formes
Exemple : dessiner des formes
...
myCanvas.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent event) {
event.gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLUE));
event.gc.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_CYAN));
event.gc.drawRectangle(0, 0, 150, 100);
event.gc.setLineStyle(SWT.LINE_DASHDOT);
event.gc.setLineWidth(20);
event.gc.drawOval(10, 10, 160, 110);
event.gc.setAlpha(150);
event.gc.fillRectangle(20, 20, 250, 150);
}
});
...
Modification de l’aspect de
transparence
ShapeGraphicContextExample.java
du projet GraphicExamples
105
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Dessiner avec Graphical Context : les textes
Graphical Context offre la possibilité de dessiner du texte
Différentes méthodes
drawString(String p, int x, int y) : écrit le texte p à la position x et y
drawString(String p, int, int y, boolean transp) : idem avec la
possibilité de forcer la transparence du fond du texte
drawText(String t, int x, int y) : idem avec la gestion de la tabulation
\t, du retour à la ligne \n et d’un caractère mnemonic &
drawText(String t, int x, int y, int flags) : idem au précédent avec
gestion des caractères
Gestion des caractères
SWT.DRAW_DELIMITER : gère le retour à la ligne \n
SWT.DRAW_TAB : gère la tabulation \t
SWT.DRAW_MNEMONIC : gère le caractère mnemonic &
SWT.DRAW_TRANSPARENT : fond transparent
106
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Dessiner avec Graphical Context : les textes
Exemple : écrire du texte
...
final String maChaine = "Voici un texte \n utilisé par deux \t\t méthodes";
myCanvas.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent event) {
event.gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLUE));
event.gc.drawString(maChaine, 0, 20);
event.gc.drawText(maChaine, 0, 40, SWT.DRAW_MNEMONIC | SWT.DRAW_TAB |
SWT.DRAW_DELIMITER) ;
}
});
...
Tabulation non prise en
compte pour le drawString
TextGraphicContextExample.java
du projet GraphicExamples
107
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Dessiner avec Graphical Context : les textes
Des méthodes pour retourner et modifier une fonte
setFont(Font myFont) : modifie la fonte courante du GC
Font getFont() : retourne la fonte courante du GC
Un objet Font peut être construit à partir
public Font(Device device, String name, int height, int style) :
construit une fonte à partir d’une police name, d’une hauteur height
et d’un style style
public Font(Device device, FontData fd) : construit une fonte à partir
d’un Device et d’un FontData (voir ci-après)
La création d’un objet Font implique la création d’un objet
natif, donc si vous en créez un vous devrez le disposer
Il existe une fonte par défaut utilisée par le GC si aucune
fonte n’est explicité Display.getSystemFont()
108
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Dessiner avec Graphical Context : les textes
Un objet FontData peut être vu comme une structure de
données des caractéristiques d’un objet Font
FontData(String pvaleur, int height, int sty) : police pvaleur, une
hauteur height et un style sty
Un objet FontData est un objet manipulant une ressource du
système et peut être disposé (automatiquement disposé si
construit à partir d’un objet Font)
Différentes méthodes :
int getHeight() : retourne la hauteur de la police de caractères
setHeight(int height) : modifie la hauteur
String getName() : retourne le nom de la police
setName(String name) : modifie le nom de la police
109
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Dessiner avec Graphical Context : les textes
bonjour
Les données de FontData ne permettent pas de connaître
les différentes hauteur d’une police au cours du dessin
Nécessite l’utilisation du FontMetrics qui ne peut être
construit, mais est accessible via le GC
FontMetrics getFontMetrics() : extraction des hauteurs d’une fonte
Les différentes hauteurs d’une fonte
int getAscent() : hauteur du corps
int getDescent() : hauteur du pied
int getLeading() : hauteur de la tête
int getHeight() : hauteur de la fonte
Leading
Ascent
Descent
Height
110
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Dessiner avec Graphical Context : les textes
En complément à l’objet FontMetrics, le Graphical Context
fournit des méthodes pour déterminer l’occupation pour une
chaîne de texte
Différentes méthodes
Point stringExtent(String value) : retourne la largeur et la hauteur
occupées par la chaîne de caractères définie par value
Point textExtent(String value) : idem en tenant compte des
caractères spécifiques \t, \n et &
Point textExtent(String value, int flags) : idem en configurant les
caractères spécifiques à prendre en compte
Ne confondez pas la hauteur d’une fonte et la
hauteur d’un texte dessiné. Il s’agit de deux
valeurs différentes. Pour la seconde, la valeur
dépend de la police, du style, …
111
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Dessiner avec Graphical Context : les textes
Exemple : respecter la dimension d’un texte
...
final String maChaine = "Voici un texte \n utilisé par deux \t\t méthodes";
myCanvas.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent event) {
event.gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLUE));
event.gc.drawString(maChaine, 0, 20);
event.gc.drawText(maChaine, 0, 40, SWT.DRAW_MNEMONIC | SWT.DRAW_TAB |
SWT.DRAW_DELIMITER) ;
Point maChainePoint = event.gc.textExtent(maChaine);
event.gc.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLACK));
event.gc.drawRectangle(0, 40, maChainePoint.x, maChainePoint.y);
}
});
...
TextSizeGraphicContextExample.java
du projet GraphicExamples
112
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Dessiner avec Graphical Context : les images
Possibilité de charger des images à partir d’un fichier sur le
disque (GIF, PNG, JPEG, TIFF, ICO, BMP et RLE)
Possibilité de créer une image pour dessiner dessus
Une image est encapsulée par la classe Image. Si vous créez
un objet Image vous devrez disposer l’objet
Différents constructeurs
Image(Device device, String filename) : construit une Image à partir
d’un fichier (chemin absolu)
Image(Device device, InputStream stream) : à partir d’un flux
Image(Device device, int width, int height) : vide avec une taille
Image(Device device, Image source, int flat) : à partir d’un autre
objet Image
Image(Device device, ImageData data) : à partir d’un ImageData
113
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Dessiner avec Graphical Context : les images
Exemple : création d’un objet Image à partir d’un fichier
...
Image image1 = new Image(Display.getDefault(), "D:/Documents
Mickey/Java/GraphicsExamples/example.jpg");
Image image2 = null;
try {
image2 = new Image(Display.getDefault(), new FileInputStream("D:/Documents
Mickey/Java/GraphicsExamples/example.jpg"));
} catch(FileNotFoundException e) {
e.printStackTrace();
}
Image image3 = new Image(Display.getDefault(),
CreateImageExample.class.getResourceAsStream("/example.jpg"));
new Label(shell, SWT.NONE).setImage(image1);
new Label(shell, SWT.NONE).setImage(image2);
new Label(shell, SWT.NONE).setImage(image3);
...
Images ajoutées directement dans
un Label, on verra dans la suite
comment dessiner une image
dans le GC
CreateImageExample.java du
projet GraphicExamples
114
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Dessiner avec Graphical Context : les images
Exemple : copie d’un objet Image
...
final Image image = new Image(Display.getDefault(),
CreateImageExample.class.getResourceAsStream("/example.jpg"));
Image copyImage = new Image(Display.getDefault(), image, SWT.IMAGE_COPY);
Image disableImage = new Image(Display.getDefault(), image, SWT.IMAGE_DISABLE);
Image grayImage = new Image(Display.getDefault(), image, SWT.IMAGE_GRAY);
new Label(shell, SWT.NONE).setImage(copyImage);
new Label(shell, SWT.NONE).setImage(disableImage);
new Label(shell, SWT.NONE).setImage(grayImage);
...
Flag qui indique comment
effectué la copie (3 valeurs
disponibles)
CopyImageExample.java du
projet GraphicExamples
115
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Dessiner avec Graphical Context : les images
Dessiner un objet Image dans le Graphical Context est
obtenu par deux méthodes
drawImage(Image image, int x, int y) : dessine une image à la
position x et y
drawImage(Image image, int sX, int sY, int sWidth, int sHeight, int
dX, int dY, int dWidth, int dHeight) : dessine une partie d’image
définie par sX, sY, sWidth, sHeight à la position dX et dY avec une
taille dWidth et dHeight
Dessiner avec un agrandissement …
...
myCanvas.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent event) {
Image myImage = new Image(Display.getDefault(),200,200);
GC gc = new GC(myImage);
gc.drawString("Bonjour tout le monde", 0, 0, true);
event.gc.drawImage(myImage, 0, 0,200,200,0,0,500,500);
event.gc.drawString("Bonjour tout le monde", 0, 50, true);
gc.dispose();
myImage.dispose();
}
});
...
Dessine tout d’abord
sur l’image puis colle
l’image dans le GC du
Canvas
ScaleTextExample.java du projet
GraphicExamples
116
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les données d’une image sont stockées dans un ImageData
byte[] data : les pixels d’une image
int alpha : la transparence
byte[] alphaData : l’alpha pour chaque pixel
int depth : le poids d’un pixel
int height, width : les dimensions d’une image
int type (SWT.IMAGE_UNDEFINED, SWT.IMAGE_BMP, …) : le format
…
Les données sont indépendantes du Device (peut être
l’écran ou l’imprimante)
Constructeurs d’un ImageData
ImageData(String filename) : construit à partir d’un nom de fichier
ImageData(InputStream filename) : construit à partir d’un stream
ImageData(int width, int height, int depth, PaletteData p) : à partir
d’une taille, profondeur et un palette
Dessiner avec Graphical Context : les images
117
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Dessiner avec Graphical Context : les images
Différentes méthodes pour manipuler ImageData
int getPixel(int x, int y) : retourne la valeur du pixel à x et y
void setPixel(int x, int y, int pixel) : modifie la valeur du pixel x et y
int getAlpha(int x, int y) : retourne l’alpha du pixel x et y
setAlpha(int x, int y, int alpha) : modifie l’alpha du pixel x et y
ImageData scaledTo(int w, int h) : retourne une nouvelle image de
taille différente (grossie ou réduite)
…
Principe pour afficher un ImageData modifié
Modifier un ImageData (setPixel, setAlpha, …)
Créer un objet Image associé à l’ImageData
Pour chaque modification de l’ImageData, créer obligatoirement un
objet Image pour afficher
Si vous créez un
objet Image,
n’oubliez pas de le
disposer si vous ne
l’utilisez plus
118
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Dessiner avec Graphical Context : les images
Exemple : un effet de transparence
...
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
shell.setText("ImagaDataAlphaColorExample");
ImageData data = new ImageData("example.jpg");
for (int i = 0; i < data.width; i++) {
for (int j = 0; j < data.height; j++) {
data.setPixel(i, j, (data.getPixel(i, j) + 110) % 255);
data.setAlpha(i, j, (data.height - j) % 254);
}
}
image = new Image(display, data);
new Label(shell, SWT.NONE).setImage(image);
...
L’ImageData est modifié,
obligation de créer un objet Image
pour afficher les modifications
ImageDataAlphaColorExample.java
du projet GraphicExamples
119
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Dessiner avec Graphical Context : Transform
Possibilité d’appliquer des matrices de transformations sur
un Graphical Context en utilisant la classe Transform
Fournit un ensemble de méthode pour effectuer
Des translations translate(float offsetX, float offsetY)
Des agrandissements scale(float scaleX, float scaleY)
Des rotations rotate(float angle)
Des transformations complexes setElements(…)
120
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Dessiner avec Graphical Context : Transform
Exemple : un effet de réflection (inspiré de Daniel Spiewak)
final Display display = Display.getDefault();
final Shell shell = new Shell(display, SWT.SHELL_TRIM );
final Image image = new Image(display,
ReflectionExample.class.getResourceAsStream(/logo.bmp));
shell.setText("Reflection");
shell.setSize(300, 200);
shell.setLayout(new FillLayout());
Canvas baseCanvas = new Canvas(shell, SWT.DOUBLE_BUFFERED);
baseCanvas.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e) {
// La suite dans le prochain transparent
}
});
...
ReflectionExample.java du projet
TransformExamples
121
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Dessiner avec Graphical Context : Transform
Exemple (suite) : un effet de réflection (Daniel Spiewak)
Pattern pattern = new Pattern(display, 0, 0, 0, e.height,
display.getSystemColor(SWT.COLOR_GRAY),
display.getSystemColor(SWT.COLOR_BLACK));
e.gc.setBackgroundPattern(pattern);
e.gc.fillRectangle(e.x, e.y, e.width, e.height);
int posX = (e.width - image.getImageData().width) / 2;
int posY = 10;
e.gc.drawImage(image, posX, posY);
Transform transform = new Transform(e.gc.getDevice());
int primaryHeight = image.getImageData().height + 10;
transform.setElements(1, 0, 0, -.5f, 0, primaryHeight + (primaryHeight / 2));
e.gc.setAlpha(100);
e.gc.setTransform(transform);
e.gc.drawImage(image, posX, posY);
transform.dispose();
pattern.dispose();
ReflectionExample.java du projet
TransformExamples
122
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les boîtes de dialogue
SWT fournit des classes (wrapper) pour la gestion des
boîtes à outils classiques
Boîte de messages
Boîte de sélection de couleur
Boîte de sélection de répertoire
Boîte de gestion de fichier
Boîte de sélection de fonte
Boîte pour l’impression
Le style de modalité pour les boîtes de dialogue pré-définies
sont obligatoirement modales
Possibilité de créer sa propre boîte de dialogue en dérivant
de la classe Dialog
Ne dérivez pas des
classes fournissant
les boîtes de
dialogue communes
123
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les boîtes de dialogue
Boîte de messages
Boîte de sélection de
couleur
Boîte de sélection de
répertoires
124
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les boîtes de dialogue
Boîte de sélection de
fichiers
Boîte de sélection de
fontes
125
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les boîtes de dialogue : message
Une boîte de message contient quatre éléments modifiables
Le texte dans la barre des titres
Le message à afficher dans la boîte
L’icône précisant l’importance du message
Les types de boutons pour fermer la boîte
Construction d’une boîte message par la classe MessageBox
MessageBox(Shell s, int type) : boite de message avec un style
Styles d’importance : ICON_ERROR, ICON_INFORMATION,
ICON_QUESTION, ICON_WARNING, ICON_WORKING
Styles de bouton : OK, CANCEL, YES, NO, RETRY, IGNORE
Différentes méthodes …
setText(String t) : modifie le titre dans la barre
int open() : affiche et retourne le code du bouton sélectionné
setMessage(String t) : message à afficher
126
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les boîtes de dialogue : message
Exemple : afficher une boîte de dialogue message
public class MessageDialogExample {
...
public MessageDialogExample(Shell shell) {
...
MessageBox mb = new MessageBox(shell, SWT.ICON_QUESTION | SWT.YES | SWT.NO
| SWT.CANCEL);
mb.setMessage("Voulez-vous apprendre SWT?");
mb.setText("Question à 2 sous");
int value = mb.open();
if (value == SWT.YES) {
System.out.println("Yes");
} else if (value == SWT.NO) {
System.out.println("No");
} else {
System.out.println("Cancel");
}
...
}
}
Pas de logique dans les
noms des méthodes !!
Pourquoi setText(…)
pour modifier le titre
d’une fenêtre????
MessageDialogExample.java du
projet DialogExamples
127
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les boîtes de dialogue : sélection de couleur
Affiche un spectre des couleurs pour en choisir une
Construction d’une boîte de couleur par la classe ColorDialog
ColorDialog(Shell s) : construit une boîte associée au Shell s
Cette boîte manipule (pour la sélection utilisateur) un objet
composantes couleurs de classe RGB
RGB(int red, int green, int blue)
Objet couleur défini par la classe Color
Color(Device d, RGB rgb)
Différentes méthodes …
RGB getRGB() : retourne la couleur sélectionnée (NULL si pas de
sélection)
setRGB(RGB rgb) : sélectionne une couleur pour l’ouverture
RGB open() : affiche et retourne la couleur sélectionnée
setText(String p) : modifie le titre
128
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les boîtes de dialogue : sélection de couleur
Exemple : afficher une boîte de sélection de couleur
public class ColorDialogExample {
...
public ColorDialogExample(shell shell) {
...
ColorDialog cd = new ColorDialog(shell);
cd.setText("Choisir une couleur");
RGB value = cd.open();
Color colorBackGround = new Color(shell.getDisplay(), value);
myButton.setBackground(colorBackGround);
colorBackGround.dispose();
...
}
}
ColorDialogExample.java du
projet DialogExamples
129
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les boîtes de dialogue : sélection de répertoire
Cette boîte permet la sélection d’un répertoire avec
possibilité d’en créer un s’il n’existe pas
Construction d’une boîte de sélection de répertoire par la
classe DirectoryDialog
DirectoryDialog(Shell s) : construit une boîte associé à s
Différentes méthodes …
String getFilterPath() : retourne le répertoire sélectionné
setMessage(String p) : modifie le message contenu dans la boîte
setText(String p) : modifie le message de la barre des titres
String open() : affiche la boîte et retourne le répertoire sélectionné
130
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les boîtes de dialogue : sélection de répertoire
Exemple : afficher une boîte de sélection de répertoire
public class DirectoryDialogExample {
...
public DirectoryDialogExample() {
...
DirectoryDialog dd = new DirectoryDialog(shell);
dd.setText("Choisir un répertoire");
dd.setMessage("Veuillez sélectionner un répertoire");
String value = mb.open();
System.out.println(value);
...
}
}
DirectoryDialogExample.java du
projet DialogExamples
131
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les boîtes de dialogue : gestion de fichier
Cette boîte permet la sélection d’un fichier pour l’ouverture
et la sauvegarde
Le style permet de paramétrer une boîte d’ouverture ou de
sauvegarde
OPEN : pour l’ouverture d’un fichier
MULTI : pour l’ouverture de plusieurs fichiers
SAVE : pour la sauvegarde d’un fichier
Construction d’une boîte par la classe FileDialog
FileDialog(Shell s) : construit une boîte associé à s
FileDialog(Shell s, int ps) : construit une boîte avec le style ps
132
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les boîtes de dialogue : gestion de fichier
Différentes méthodes …
String getFileName() : retourne le fichier traité
String[] getFileName() : retourne les fichiers (pour le style MULTI)
String open() : affiche la boîte et retourne le fichier traité
setText(String p) : modifie le titre de la boîte de gestion de fichier
Possibilité de filtrer les fichiers qui apparaîtront dans la boîte
setFilterNames(String[] names) : description des noms de filtres
setFilterExtensions(String[] ex) : description des filtres
Exemples manipulation des filtres
openSaveDialog.setFilterNames(new String[] {
"Image BMP (*.bmp)",
"Image JPG (*.jpg)"
});
openSaveDialog.setFilterExtensions(new String[] {
"*.bmp",
"*.jpg"
});
Définition des noms
de filtres
Définition des filtres
133
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les boîtes de dialogue : gestion de fichier
Exemple : afficher une boîte de gestion de fichiers
public class FileDialogExample {
...
public FileDialogExample() {
...
Filedialog fd = new Filedialog(shell, SWT.OPEN);
fd.setFilterNames(new String[] {
"Image BMP (*.bmp)",
"Image JPG (*.jpg)"
});
fd.setFilterExtensions(new String[] {
"*.bmp",
"*.jpg"
});
fd.setText("Choisir un fichier");
String value = fd.open();
System.out.println(value);
...
}
}
FileDialogExample.java du projet
DialogExamples
134
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les boîtes de dialogue : sélection de fonte
Cette boîte permet la sélection d’une fonte
Construction d’une boîte par la classe FontDialog
FontDialog(Shell s) : construit une boîte associé à s
Cette boîte manipule (pour la sélection utilisateur) un objet
de classe FontData pour manipuler une fonte
La couleur de la fonte n’est pas stockée dans FontData et
par conséquent la boîte retourne un objet RGB
Différentes méthodes …
FontData[] getFontList() : contient la liste des données d’une fonte
setFontList(FontData[] p) : modifie les informations d’une fonte
FontData open() : affiche la boîte et retourne la fonte
RGB getRGB() : retourne la couleur sélectionnée
setText(String t) : modifie le titre de la boîte
135
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Les boîtes de dialogue : sélection de fonte
Exemple : afficher une boîte de sélection de fonte
public class FontDialogExample {
...
public FontDialogExample() {
...
FontDialog fd = new FontDialog(shell);
fd.setText("Choisir une fonte");
FontData value = fd.open();
// Affichie le nom de la police utilisée
System.out.println(value.getName());
...
}
}
FontDialogExample.java du projet
DialogExamples
136
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
UI-thread et SWTException
Le processus créé par le Display est un processus graphique
appelé UI-thread
UI-thread s’occupe de lire et dispatcher les événements
issus du système d’exploitation puis d’invoquer les écouteurs
associés à ces événements
Pour les traitements important à effectuer, utiliser un thread
séparé (noté task-thread) au UI-thread de manière à ce que
le UI-thread puisse traiter les événements du système
Seul le UI-thread peut manipuler les éléments graphiques et
tout accès à l’extérieur du UI-thread engendre une
exception de type : org.eclipse.swt.SWTException
137
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
UI-thread et SWTException
Pour résoudre le problème de SWTException il faut inclure
les appels graphiques dans le UI-thread
Display fournit deux méthodes
syncExec(Runnable r) : appel synchrone
asyncExec(Runnable r) : appel asynchrone
Runnable est un objet thread en charge de la modification
graphique contenant une méthode run()
void run() { code qui modifie l’IHM }
Avec un appel synchrone task-thread est en attente tant que
le code contenu dans le run n’est pas terminé
Avec un appel asynchrone task-thread continue à s’exécuter
en parallèle du code contenu dans le run
138
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
UI-thread et SWTException
Deux exemples qui présentent un appel synchrone et un
appel asynchrone
Exemple pour l’appel synchrone
Un Thread en charge de gérer un compteur (3 à 0)
A chaque occurrence une boîte de message est lancée de manière
synchrone
Tant que la boîte de message n’est pas fermé le thread compteur est
bloqué
Exemple pour l’appel asynchrone
Un Thread qui gère un compteur (100 à 0)
A chaque occurrence une barre de progression est avertie de
manière asynchrone
La modification de la barre de progression n’influence pas le
compteur (l’IHM ne bloque pas le modèle)
139
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
UI-thread et SWTException
Exemple : affichage d’une boîte de dialogue pour un appel
synchrone
public class SynchroneExample {
private Timer t;
public SynchroneExample() {
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setLayout(new FillLayout(SWT.VERTICAL));
Button myButton = new Button(shell, SWT.FLAT);
myButton.setText("Go");
myButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
if (t != null) {
t.cancel();
}
t = new Timer();
t.schedule(new TimerTask() {
// Voir transparent suivant ...
}, 0, 1*1000);
}
});
...
}
...
}
SynchroneExample.java du
projet DialogExamples
140
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
UI-thread et SWTException
Exemple (suite): affichage d’une boîte de dialogue pour un
appel synchrone
t.schedule(new TimerTask() {
int nbrRepetitions = 3;
public void run() {
if (nbrRepetitions > 0) {
System.out.println("Ca bosse dur!");
nbrRepetitions--;
display.syncExec(new Runnable() {
public void run() {
MessageBox d = new MessageBox(shell, SWT.YES);
d.setText("Mon Titre");
d.setMessage("");
d.open();
}
});
System.out.println("Ici");
} else {
System.out.println("Terminé!");
t.cancel();
}
}
}, 0, 1*1000);
141
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
UI-thread et SWTException
Exemple : barre de progression pour un appel asynchrone
public class ASynchroneExample {
private Timer t;
public ASynchroneExample() {
...
Button myButton = new Button(shell, SWT.FLAT);
final ProgressBar myProgressBar = new ProgressBar(shell, SWT.NONE);
myProgressBar.setMaximum(100);
myProgressBar.setMinimum(0);
myProgressBar.setSelection(100);
myButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
if (t != null) {
t.cancel();
}
t = new Timer();
t.schedule(new TimerTask() {
// Voir transparent suivant ...
}, 0, 1 * 10);
}
});
...
}
...
}
ASynchroneExample.java du
projet DialogExamples
142
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
UI-thread et SWTException
Exemple (suite) : barre de progression pour un appel
asynchrone
t.schedule(new TimerTask() {
int nbrRepetitions = 100;
public void run() {
display.asyncExec(new Runnable(){
public void run() {
myProgressBar.setSelection(nbrRepetitions);
}
});
if (nbrRepetitions > 0) {
nbrRepetitions--;
} else {
System.out.println("Terminé");
t.cancel();
}
}
}, 0, 1 * 10);
ASynchroneExample.java du
projet DialogExamples
143
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Cohabitation entre composants Swing et SWT
L’API SWT permet d’intégrer des composants basés sur la
boîte à outils Swing
L’avantage est de pouvoir intégrer des
composants qui n’existe pas dans la boîte à outils SWT
L’inconvénient est de se trouver avec des composants
hétérogènes dans la manière de les utiliser
Abonnement à des écouteurs différents
Gestion du « dessin » différent
Agents de placement différents
Bref beaucoup de différences
Evitez tant que possible
de mixer des composants
Swing avec SWT
144
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Cohabitation entre composants Swing et SWT
Exemple : intégrer des composants JFreeCharts et JGraph
JGraph
JFreeCharts
145
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Cohabitation entre composants Swing et SWT
L’intégration de composants Swing se fait par l’intermédiaire
de la couche bas niveau de Swing c’est-à-dire via AWT
Principe général
Le point d’entrée de Swing vers SWT est obtenu par l’intermédiaire
d’une Frame (java.awt.frame)
Tous composants Swing doit être contenus dans une Frame (ou
plusieurs)
Il faut voir la Frame comme un conteneur au même titre que le
Composite en SWT
L’handle de la Frame (identifiant) est récupéré puis utilisé par SWT
pour ajouter le contenu de la Frame vers un Composite SWT
Exemple : il est possible d’intégrer
n’importe quelle application Win32
dans du SWT par l’intermédiaire des
handles de fenêtre : à suivre …
146
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Cohabitation entre composants Swing et SWT
L’API SWT fournit une API spécifique pour l’intégration de
composants Swing
package : org.eclipse.swt.awt
classe : SWT_AWT
Les méthodes de la classe SWT_AWT
static Frame new_Frame(Composite parent) : construit une Frame
contenant les composants Swing, parent est le conteneur SWT qui
contiendra la Frame créée
La Frame créée est la racine des composants Swing
Le Composite parent doit avoir le style SWT.EMBEDDED
147
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Cohabitation entre composants Swing et SWT
Exemple : SWT + Swing = SWingT ?
public class SWTAWTExample {
...
public SWTAWTExample() {
Display display = new Display();
Shell shell = new Shell(display);
GridLayout layout = new GridLayout(1, false);
shell.setLayout(layout);
shell.setText("SWT and Swing/AWT Example");
Label separator1 = new Label(shell, SWT.NONE);
separator1.setText("Mon Message en SWT");
Composite awtComp = new Composite(shell,SWT.EMBEDDED);
GridData myGridData = new GridData(GridData.FILL_BOTH);
awtComp.setLayoutData(myGridData);
Frame awtFrame = SWT_AWT.new_Frame(awtComp);
JTextField textField = new JTextField("Saisir une valeur dans du Swing");
awtFrame.add(textField);
...
}
}
Composant Swing
Composant SWT
SWTAWTExample.java du projet
SWTAndSwingEamples
148
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Cohabitation entre composants Swing et SWT
Exemple : Winrar dans une Shell
Utilisation de la classe org.eclipse.swt.internal.win32.OS
Shell SWT
Button SWT
Application
WINRAR
Peut très
bien être du
natif MAC OS,
Linux, …
149
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Cohabitation entre composants Swing et SWT
Une des grandes forces de la boîte à outils Swing concerne
l’API Java 2D
Le portage de composants Swing vers SWT reste facile,
mais qu’en est-il d’un code Java 2D à migrer ou adapter ?
Une solution est fournie par la classe Graphics2DRenderer
www-128.ibm.com/developerworks/java/library/j-2dswt/
Principe
Construire un objet Graphics2DRenderer
Récupérer le GC d’un composant SWT (par exemple un Canvas)
Initialiser l’objet Graphics2DRenderer avec le GC
Utiliser l’API Java2D de Sun
Générer un rendu des opérations Java2D dans le GC par
l’intermédiaire du Graphics2DRenderer
150
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Cohabitation entre composants Swing et SWT
Principe de fonctionnement de Graphics2DRenderer
151
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Cohabitation entre composants Swing et SWT
Une autre façon de faire cohabiter des composants Swing
est d’utiliser la librairie SwingWT
SwingWT fournit une re-implémentation des composants
Swing en SWT
Adresse : swingwt.sourceforge.net
La logique de l’API Swing est respectée
javax.swing.JButton en Swing
swingwt.swing.JButton en SwingWT
Avantages
Fournir des plug-ins Eclipse en utilisant les composants types Swing
Refactoring très facile d’anciennes applications Swing
Compilation en code natif avec GCJ
Inconvénients
Retard par rapport aux nouveautés des JDK
152
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Cohabitation entre composants Swing et SWT
Demo SwingSet en
utilisant SwintWT
(refactoring
immédiat de
l’application)
153
SWT - M. Baron - Page
mickael-baron.fr mickaelbaron
Bilan …
Premières impressions …
Pas aussi souple que Swing (limitée par rapport au système hôte)
Difficile de réaliser des effets graphiques (absence de GlassPane :-( )
Venant du monde Swing la tentation d’incorporer des composants
Swing dans du SWT est forte (SWT pas aussi fournie en composant)
Sur le net, peu de « hacker » SWT ;-)
Parfois, l’API SWT n’est pas un modèle de programmation !!!
Les choses non étudiées, prochainement …
La gestion de l’impression
Approfondir Graphical Context (Transformation [scale, rotate, …])
Appels à des fonctions systèmes via JNI/JNA et la classe OS
…