Vous êtes sur la page 1sur 36

Cours IHM-1

JavaFX
3 - Architecture
Concepts techniques
Jacques BAPST
jacques.bapst@hefr.ch

Une premire immersion


( Hello World ! )

IHM-1 FX03

Jacques BAPST

Premire application [1]


Comment se prsente une application JavaFX ?
(petite immersion avant de dcrire plus en dtail les concepts de base).

L'application est code en crant une sous-classe de Application.


La fentre principale d'une application est reprsente par un objet
de type Stage qui est fourni par le
systme au lancement de l'application.
L'interface est reprsente par un objet
de type Scene qu'il faut crer et associer
la fentre (Stage).
La scne est compose des diffrents
lments de l'interface graphique
(composants de l'interface graphique)
qui sont des objets de type Node.
La mthode start() construit le tout.
IHM-1 FX03

Jacques BAPST

Mtaphore de la salle de spectacle


Les lments structurels principaux d'une application JavaFX se
basent sur la mtaphore de la salle de spectacle (theater).
Remarque : En franais, on utilise le terme 'scne' pour parler de l'endroit o se passe
le spectacle (l'estrade, les planches) mais
galement pour parler de ce qui s'y droule
(jouer ou tourner une scne) ce qui peut
conduire un peu de confusion avec cette
mtaphore.

Stage

: L'endroit o a lieu l'action, o


se droule la scne

Scene

: Tableau ou squence faisant


intervenir les acteurs

Controls : Acteurs, figurants, lments du


Components dcor, (lments actifs/passifs)
Nodes
qui font partie de la scne en
Widgets
train d'tre joue.
IHM-1 FX03

Jacques BAPST

Hello World [1]


Une premire application, le traditionnel Hello World !
public class HelloWorld extends Application {
//--------------------------------------------@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("My First JavaFX App");
BorderPane root = new BorderPane();
Button btnHello = new Button("Hello World");
root.setCenter(btnHello);
Scene scene = new Scene(root, 250, 100);
primaryStage.setScene(scene);
primaryStage.show();
}
//--------------------------------------------public static void main(String[] args) {
launch(args);
}
}

IHM-1 FX03

Jacques BAPST

Hello World [2]


JavaFX tant intgr la plateforme de base Java, aucune librairie
externe n'est ncessaire au fonctionnement de l'exemple prcdent.
Un certain nombre d'importations doivent cependant tre
effectues (on y retrouve les classes principales Application, Stage,
Scene ainsi que les composants BorderPane et Button) :

import
import
import
import
import

javafx.application.Application;
javafx.scene.Scene;
javafx.scene.control.Button;
javafx.scene.layout.BorderPane;
javafx.stage.Stage;

En principe, Eclipse
s'en charge
automatiquement

Dans cet exemple, la mthode main() lance uniquement la mthode


statique launch() (qui est hrite de Application).
Dans une application un peu plus complexe, elle pourrait effectuer
d'autres oprations d'initialisation avant l'invoquer launch().

IHM-1 FX03

Jacques BAPST

Cycle de vie d'une application [1]


Le point d'entre d'une application JavaFX est constitu de l'instance
de la classe Application (gnralement une sous-classe).
Lors du lancement d'une application par la mthode statique
Application.launch() le runtime JavaFX effectue les oprations
suivantes :
1. Cre une instance de la classe qui hrite de Application
2. Appelle la mthode init()
3. Appelle la mthode start() et lui passe en paramtre une instance
de Stage (qui reprsente la fentre principale [primary stage])
4. Attend ensuite que l'application se termine; cela se produit lorsque :

La dernire fentre de l'application a t ferme


(et Platform.isImplicitExit() retourne true)
L'application appelle Platform.exit() (ne pas utiliser System.Exit())

5. Appelle la mthode stop()

IHM-1 FX03

Jacques BAPST

Cycle de vie d'une application [2]


La mthode launch() est gnralement lance depuis la mthode
main(). Elle est implicitement lance s'il n'y a pas de mthode
main() (ce qui est tolr depuis Java 8).
Des paramtres de lancement peuvent tre rcuprs en invoquant
la mthode getParameters() dans la mthode init() ou
ultrieurement.
Invoquer ensuite getRaw() ou get pour obtenir la liste (List<String>)

La mthode start() est abstraite et doit tre redfinie.

Les mthodes init() et stop() ne doivent pas obligatoirement tre


redfinies (par dfaut elle ne font rien).
La mthode start() s'excute dans le JavaFX Application Thread.
C'est dans ce thread que doit tre construite l'interface et que
doivent tre excutes toutes les oprations qui agissent sur des
composants attachs une scne (live components).
IHM-1 FX03

Jacques BAPST

Traiter une action de l'utilisateur


Dans l'exemple Hello World, pour que le clic sur le bouton dclenche
une action, il faut traiter l'vnement associ.
La mthode setOnAction() du bouton permet d'enregistrer un
Event Handler (c'est une interface fonctionnelle possdant la mthode
handle(event) qui dfinit l'action effectuer).
public void start(Stage primaryStage) {
primaryStage.setTitle("My First JavaFX App");
BorderPane root = new BorderPane();
Button btnHello = new Button("Say Hello");
btnHello.setOnAction(
event -> System.out.println("Hello World !"));
root.setCenter(btnHello);
Scene scene = new Scene(root, 250, 100);
primaryStage.setScene(scene);
primaryStage.show();
}
IHM-1 FX03

Jacques BAPST

Proprits

IHM-1 FX03

Jacques BAPST

10

Notion de proprit [1]


La notion de "proprit" (property) est trs prsente dans JavaFX.
Une proprit est un lment d'une classe que l'on peut manipuler
l'aide de getters (lecture) et de setters (criture).
Les proprits sont gnralement reprsentes par des attributs de
la classe mais elles pourraient aussi tre stockes dans une base de
donnes ou autre systme d'information.
En plus des mthodes get() et set(), les proprits JavaFX
possdent une troisime mthode Property() qui retourne un
objet qui implmente l'interface Property [ : nom de la proprit].
Intrt des proprits :
Elles peuvent tre lies entre-elles (Binding), c--d que le changement
d'une proprit entrane automatiquement la mise jour d'une autre.
Elles peuvent dclencher un vnement lorsque leur valeur change et
un gestionnaire d'vnement (Listener) peut ragir en consquence.
IHM-1 FX03

Jacques BAPST

11

Notion de proprit [2]


Exemple d'une classe dfinissant la proprit balance (solde) pour
un compte bancaire.
public class BankAccount {
private DoubleProperty balance = new SimpleDoubleProperty();
public final double getBalance() {
return balance.get();
}
public final void setBalance(double amount) {
balance.set(amount);
}

public final DoubleProperty balanceProperty() {


return balance;
}
. . .
}
IHM-1 FX03

Jacques BAPST

12

Notion de proprit [3]


La classe abstraite DoubleProperty permet d'emballer une valeur
de type double et d'offrir des mthodes pour consulter et modifier
la valeur mais galement pour "observer" et "lier" les changements.
SimpleDoubleProperty est une classe concrte prdfinie.

La plateforme Java offre des classes similaires pour la plupart des


types primitifs, les chanes de caractres, certaines collections ainsi
que le type Object qui peut couvrir tous les autres types.
IntegerProperty

/
StringProperty
/
ListProperty<E> /
ObjectProperty<T> /

SimpleIntegerProperty
SimpleStringProperty
SimpleListProperty<E>
SimpleObjectProperty<T>

...

Des classes existent galement pour dfinir des proprits read-only


ReadOnlyIntegerWrapper, ReadOnlyIntegerProperty
...
IHM-1 FX03

Jacques BAPST

13

Observation des proprits [1]


Toutes les classes de proprits implmentent l'interface
Observable et offrent de ce fait, la possibilit d'enregistrer des
observateurs (Listener) qui seront avertis lorsque la valeur de la
proprit change.
Une instance de l'interface fonctionnelle ChangeListener<T>
pourra ainsi tre cre pour ragir un tel changement. La mthode
changed() sera alors invoque et recevra en paramtre la valeur
observe ainsi que l'ancienne et la nouvelle valeur de la proprit.
DoubleProperty sum = account.balanceProperty();

sum.addListener( (ObservableValue<? extends Number> obsVal,


Number
oldVal,
Number
newVal ) ->
{
//--- ChangeListener code
System.out.println(oldVal+" becomes "+ newVal);
. . .
} );
IHM-1 FX03

Jacques BAPST

14

< < <

C o mp l me nt

> > >

Observation des proprits [2]


Remarque: Dans l'exemple prcdent, une expression lambda est utilise
pour implmenter la mthode changed(). On pourrait galement
utiliser une classe anonyme ou crer l'instance d'une classe
"ordinaire" qui implmente l'interface ChangeListener<T>.

L'interface fonctionnelle InvalidationListener<T> permet


galement de ragir aux changements des valeurs de proprits
dans les situations o les proprits sont calcules partir d'autres
et que l'on veut viter d'effectuer les calculs chaque changement.
Avec cette interface, c'est la mthode invalidated(Observable o)
qui est invoque lorsqu'un changement potentiel de la valeur de la
proprit est intervenu.
Cette mthode peut cependant tre invoque alors que le rsultat
observ n'a finalement pas chang (cela dpend des oprations
effectues).
IHM-1 FX03

Jacques BAPST

15

Proprits des composants


Les composants utiliss dans les interfaces graphiques (boutons,
champs texte, cases cocher, sliders, etc.) possdent tous de
nombreuses proprits.
Pour chacun des composants, la documentation (Javadoc) dcrit
dans une des rubriques (Property Summary) la liste des proprits
de la classe concerne ainsi que celles qui sont hrites.

IHM-1 FX03

Jacques BAPST

16

Lier des proprits [1]


Un des avantages des proprits JavaFX est la possibilit de pouvoir
les lier entre-elles. Ce mcanisme, appel binding, permet de mettre
jour automatiquement une proprit en fonction d'une autre.
Dans les interfaces utilisateurs, on a frquemment ce type de liens.
Par exemple, lorsqu'on dplace le curseur
d'un slider, la valeur d'un champ texte
changera (ou la luminosit d'une image,
la taille d'un graphique, le niveau sonore,
etc.).

Il est possible de lier deux proprits A


et B de manire
Unidirectionnelle : un changement de A entranera un changement
de B mais pas l'inverse (B non modifiable autrement)
Bidirectionnelle : un changement de A entranera un changement
de B et rciproquement (les deux sont modifiables)
IHM-1 FX03

Jacques BAPST

17

Lier des proprits [2]


Illustration des liens possibles entre deux proprits A et B :
A

A
B.bindBidirectional(A)
B.bind(A)

ou

A.bindBidirectional(B)

Liaison unidirectionnelle

Liaison bidirectionnelle

(la valeur de la proprit B


dpend de la valeur de la
proprit A)

(la valeur de la proprit B


dpend de la valeur de la
proprit A et inversement)

IHM-1 FX03

Jacques BAPST

18

Lier des proprits [3]


La mthode bind() permet de crer un lien unidirectionnel.
La mthode doit tre appele sur la proprit qui sera "soumise"
l'autre (celle qui est passe en paramtre).
BankAccount account = new BankAccount();

Slider

slider

= new Slider();

account.balanceProperty().bind(slider.valueProperty());

Dans cet exemple la valeur du solde du compte bancaire est lie


(asservie) la position du curseur du slider. Si l'on tente de modifier
le solde d'une autre manire (avec setBalance() par exemple) une
exception sera gnre.
Une liaison bidirectionnelle s'effectue de manire similaire, mais en
utilisant la mthode bindBidirectional().
Pour supprimer le lien : unbind() et unbindBidirectional()
IHM-1 FX03

Jacques BAPST

19

Lier des proprits [4]


Une proprit ne peut tre lie (asservie) qu' une seule autre si le
lien est unidirectionnel (bind()). Par contre, les liens bidirectionnels
(bindBidirectional()) peuvent tre multiples.
Parfois, une proprit dpend d'une autre mais avec une relation
plus complexe. Il est ainsi possible de crer des proprits calcules.
Deux techniques sont disposition (elles peuvent tre combines) :
Utiliser la classe utilitaire Bindings qui possde de nombreuses
mthodes statiques permettant d'effectuer des oprations.
Utiliser les mthodes disponibles dans les classes qui reprsentent
les proprits; ces mthodes peuvent tre chanes (Fluent API).

Des oprations de conversions sont parfois ncessaires si le type des


proprits lier n'est pas le mme. Par exemple pour lier un champ
texte (StringProperty) un slider dont la valeur est numrique
(DoubleProperty).
IHM-1 FX03

Jacques BAPST

20

Lier des proprits [5]


Exemple de binding permettant de coupler la valeur d'un slider
(Area) aux valeurs d'entre de deux autres sliders (Width et Height)
En utilisant les mthodes statiques de la classe Bindings :
Slider
Slider
Slider

widthSlider = new Slider();


heightSlider = new Slider();
areaSlider
= new Slider();

// Input
// Input
// Ouput

DoubleProperty widthPty = widthSlider.valueProperty();


DoubleProperty heightPty = heightSlider.valueProperty();
DoubleProperty areaPty
= areaSlider.valueProperty();

areaPty.bind(Bindings.multiply(widthPty, heightPty));

Width Slider

Height Slider

Devient non ditable


car li aux deux autres

IHM-1 FX03

Area Slider
(produit des 2 valeurs)

Jacques BAPST

21

Lier des proprits [6]


Mme exemple, en utilisant des mthodes chanes (Fluent API) :
Slider
Slider
Slider

widthSlider = new Slider();


heightSlider = new Slider();
areaSlider
= new Slider();

// Input
// Input
// Ouput

DoubleProperty widthPty = widthSlider.valueProperty();


DoubleProperty heightPty = heightSlider.valueProperty();
DoubleProperty areaPty
= areaSlider.valueProperty();
areaPty.bind(widthPty.multiply(heightPty));

Un jeu d'oprations est disponible aussi bien avec la classe Bindings


qu'avec les mthodes chanables.

min(), max()
equal(), notEqual(), lessThan(), lessThanOrEqual(),
isNull(), isNotNull(), isEmpty(), isNotEmpty()
convert(), concat(), format(),
et beaucoup d'autres . . .

IHM-1 FX03

Jacques BAPST

22

Lier des proprits [7]


Si les oprations disponibles dans les API, dites de haut-niveau, ne
permettent pas d'exprimer la relation entre les proprits, il est
possible de dfinir une liaison de plus bas niveau (low-level binding)
en redfinissant la mthode abstraite computeValue() d'une des
classes de binding (DoubleBinding, BooleanBinding, StringBinding, ).
DoubleBinding complexBinding = new DoubleBinding() {
{
//--- Set listeners to 'in'-properties
super.bind(aSlider.valueProperty(), bSlider.valueProperty());
}
@Override //--- Compute 'out' value
protected double computeValue() {
double w = aSlider.valueProperty().get();
double h = bSlider.valueProperty().get();
return Math.sqrt(h) * Math.pow(w, 3);
}
};
outSlider.valueProperty().bind(complexBinding);

IHM-1 FX03

Jacques BAPST

// Do the binding

23

Architecture JavaFX
Concepts techniques

IHM-1 FX03

Jacques BAPST

24

Architecture technique [1]


L'architecture technique de la plateforme JavaFX est compose de
plusieurs couches (library stack) qui reposent sur la machine virtuelle
Java (JVM).
Applications JavaFX
Public Layer
Private Layer
Native Layer

Les dveloppeurs ne devrait utiliser que la couche (API) publique car


les couches infrieures sont susceptibles de subir des changements
importants au fil des versions (sans aucune garantie de compatibilit).
Les "briques" intermdiaires ne seront donc pas dcrites dans ce
cours.
IHM-1 FX03

Jacques BAPST

25

lments d'une application


Structure gnrale d'une
application JavaFX.

Stage

Scene

Component
Control

Container
Layout
Component
Control

Component
Control

Container
Layout

...

Component
Control

Container
Layout

Component
Control

...

Component
Control

...

...

...

Graphe de scne

(dfini en Java ou avec FXML)


IHM-1 FX03

Jacques BAPST

26

Graphe de scne [1]


Le graphe de scne (scene graph) est une notion importante qui
reprsente la structure hirarchique de l'interface graphique.
Techniquement, c'est un graphe acyclique orient (arbre orient)
avec :
une racine (root)
des nuds (nodes)
des arcs qui reprsentent les relations parent-enfant

Les nuds (nodes) peuvent tre


de trois types :
Racine
Nud intermdiaire
Feuille (leaf)

IHM-1 FX03

Jacques BAPST

27

Graphe de scne [2]


Les feuilles de l'arbre sont gnralement constitus de composants
visibles (boutons, champs texte, ) et les nuds intermdiaires (y
compris la racine) sont gnralement des lments de structuration
(souvent invisibles), typiquement des conteneurs ou panneaux de
diffrents types (HBox, VBox, BorderPane, ).

IHM-1 FX03

Jacques BAPST

28

Graphe de scne [3]


Tous les lments contenus dans un graphe de scne sont des objets
qui ont pour classe parente la classe Node.
La classe Node comporte de nombreuses sous-classes :

Conteneurs (LayoutPanes) non reprsents


(voir plus loin)

Simplifi !
(il y a des classes intermdiaires)

IHM-1 FX03

Jacques BAPST

29

Graphe de scne [4]


Parmi les sous-classes de Node on distingue diffrentes familles :
Les formes primitives (Shape) 2D et 3D

Line, Circle, Rectangle, Box, Cylinder,

Les conteneurs (Layout-Pane) qui se chargent


de la disposition (layout) des composants enfants
et qui ont comme classe parente Pane.

AnchorPane, BorderPane, GridPane, HBox, VBox,

Les composants standard (Controls) qui


tendent la classe Control.

Label, Button, TextField, ComboBox,

Les composants spcialiss qui sont ddis


un domaine particulier (par exemple : lecteur
multimdia, navigateur web, etc.).

MediaView, WebView, ImageView, Canvas, Chart,

IHM-1 FX03

Jacques BAPST

30

Conteneurs
Les conteneurs (Layout-Pane) reprsentent une famille importante
parmi les sous-classes de Node. Ils ont pour classe parente Pane et
Region qui possdent de nombreuses proprits et mthodes
hrites par tous les conteneurs.

...

IHM-1 FX03

Jacques BAPST

31

Region - Structure visuelle [1]


La classe Region est la classe parente des composants (Controls) et
des conteneurs (Layout-Panes).
Elle dfinit des proprits qui affectent la reprsentation visuelle.
Les diffrentes zones d'une rgion sont bases sur la spcification
du Box-Model CSS 3 (selon normalisation du W3C).
Elles dfinissent les notions Margin, Border, Padding, Insets, Content
Les zones Border et
Padding dfinissent
les Insets (encarts)
de la rgion

Les composants
enfants sont ajouts
dans la zone Content

IHM-1 FX03

Jacques BAPST

32

Region - Structure visuelle [2]


Comme la classe Region est la classe parente de tous les conteneurs
et de tous les composants, ses proprits sont hrites et peuvent
s'appliquer une grande varit d'lments qui sont utiliss pour
crer les interfaces.
Parmi ces proprits, on peut mentionner :
border
Bordure autour de la rgion
background
Couleur ou image d'arrire-plan de la rgion
padding
Marge (espace) autour du contenu de la rgion

L'utilisation et le codage des proprits border et background sont


expliqus plus en dtail dans le chapitre suivant consacr aux
conteneurs et layout-panes ( la section Disposition des composants Gnralits).
IHM-1 FX03

Jacques BAPST

33

Style Look and Feel [1]


La notion de style, skin, thme ou look and feel (L&F) caractrise
l'ensemble des aspects visuels de l'interface graphique et de ses
composants (forme, couleur, texture, ombre, police de caractres, ).
En JavaFX, le style des composants est dfini par des feuilles de style
de type CSS. Il est ainsi possible de changer globalement l'aspect de
l'interface sans avoir modifier le code de l'application.
La mthode setUserAgentStylesheet() de la classe Application
permet d'indiquer l'URL de la feuille de style qui est appliquer
globalement.
Deux styles, nomms Modena et Caspian, sont prdfinis et sont
associs aux constantes :
STYLESHEET_MODENA
STYLESHEET_CASPIAN

IHM-1 FX03

: Utilis par dfaut depuis JavaFX 8


: A t dfini pour JavaFX 2

Jacques BAPST

34

Style Look and Feel [2]


Style Modena sur diffrents OS.

IHM-1 FX03

Jacques BAPST

35

Style Look and Feel [3]


Le style utilis par dfaut peut voluer au fil des versions de JavaFX.
Si l'on veut fixer ou changer le look and feel des interfaces, on peut
le faire au dmarrage de l'application :
@Override
public void start(Stage primaryStage) {
. . .
setUserAgentStylesheet(STYLESHEET_CASPIAN);
. . .

Des styles externes (third-party) peuvent galement tre imports


et appliqus. On trouve diffrentes ralisations, par exemple :

Apple Aqua
Microsoft Modern UI
Twitter Bootstrap
Flatter (Embedded UI),

IHM-1 FX03

(AquaFX)
(JMetro)
(Fextile)
...

Windows-7 Aero

Jacques BAPST

(AeroFX)

36