36
Cours IHM - 1 JavaFX Jacques BAPST [email protected] 3 - Architecture Concepts techniques

Java FX Partie3

Embed Size (px)

DESCRIPTION

Java FX Partie3

Citation preview

Page 1: Java FX Partie3

Cours IHM-1JavaFX

Jacques BAPST

[email protected]

3 - ArchitectureConcepts techniques

Page 2: Java FX Partie3

Une première immersion( Hello World ! )

IHM-1 – FX03 – Jacques BAPST 2

Page 3: Java FX Partie3

Première application [1]

Comment se présente une application JavaFX ?(petite immersion avant de décrire plus en détail les concepts de base).

L'application est codée en créant une sous-classe de Application.

La fenêtre principale d'une application est représentée par un objet de type Stage qui est fourni par lesystème au lancement de l'application.

L'interface est représentée par un objetde type Scene qu'il faut créer et associerà la fenêtre (Stage).

La scène est composée des différentséléments de l'interface graphique(composants de l'interface graphique)qui sont des objets de type Node.

La méthode start() construit le tout.

IHM-1 – FX03 – Jacques BAPST 3

Page 4: Java FX Partie3

Métaphore de la salle de spectacle

Les éléments structurels principaux d'une application JavaFX se basent sur la métaphore de la salle de spectacle (theater).

Remarque : En français, on utilise le terme 'scène' pour parler de l'endroit où se passele spectacle (l'estrade, les planches) maiségalement pour parler de ce qui s'y déroule(jouer ou tourner une scène) ce qui peutconduire à un peu de confusion avec cettemétaphore.

Stage : L'endroit où a lieu l'action, oùse déroule la scène

Scene : Tableau ou séquence faisantintervenir les acteurs

Controls : Acteurs, figurants, éléments duComponents décor, … (éléments actifs/passifs)Nodes qui font partie de la scène enWidgets train d'être jouée.

IHM-1 – FX03 – Jacques BAPST 4

Page 5: Java FX Partie3

Hello World [1]

Une première application, le traditionnel Hello World !

IHM-1 – FX03 – Jacques BAPST 5

public class HelloWorld extends Application {//---------------------------------------------@Overridepublic 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);

}}

Page 6: Java FX Partie3

Hello World [2]

JavaFX étant intégré à la plateforme de base Java, aucune librairie externe n'est nécessaire au fonctionnement de l'exemple précédent.

Un certain nombre d'importations doivent cependant être effectuées (on y retrouve les classes principales Application, Stage, Scene ainsi que les composants BorderPane et Button) :• import javafx.application.Application;• import javafx.scene.Scene;• import javafx.scene.control.Button;• import javafx.scene.layout.BorderPane;• import javafx.stage.Stage;

Dans cet exemple, la méthode main() lance uniquement la méthode statique launch() (qui est héritée de Application).

• Dans une application un peu plus complexe, elle pourrait effectuer d'autres opérations d'initialisation avant l'invoquer launch().

IHM-1 – FX03 – Jacques BAPST 6

En principe, Eclipses'en charge

automatiquement

Page 7: Java FX Partie3

Cycle de vie d'une application [1]

Le point d'entrée d'une application JavaFX est constitué de l'instance de la classe Application (généralement une sous-classe).

Lors du lancement d'une application par la méthode statique Application.launch() le runtime JavaFX effectue les opérations suivantes :

1. Crée une instance de la classe qui hérite de Application

2. Appelle la méthode init()

3. Appelle la méthode start() et lui passe en paramètre une instance de Stage (qui représente la fenêtre principale [primary stage])

4. Attend ensuite que l'application se termine; cela se produit lorsque : La dernière fenêtre de l'application a été fermée

(et Platform.isImplicitExit() retourne true)

L'application appelle Platform.exit() (ne pas utiliser System.Exit())

5. Appelle la méthode stop()

IHM-1 – FX03 – Jacques BAPST 7

Page 8: Java FX Partie3

Cycle de vie d'une application [2]

La méthode launch() est généralement lancée depuis la méthode main(). Elle est implicitement lancée s'il n'y a pas de méthode main() (ce qui est toléré depuis Java 8).

Des paramètres de lancement peuvent être récupérés en invoquant la méthode getParameters() dans la méthode init() ou ultérieurement.• Invoquer ensuite getRaw() ou get… pour obtenir la liste (List<String>)

La méthode start() est abstraite et doit être redéfinie.

Les méthodes init() et stop() ne doivent pas obligatoirement être redéfinies (par défaut elle ne font rien).

La méthode start() s'exécute dans le JavaFX Application Thread. C'est dans ce thread que doit être construite l'interface et que doivent être exécutées toutes les opérations qui agissent sur des composants attachés à une scène (live components).

IHM-1 – FX03 – Jacques BAPST 8

Page 9: Java FX Partie3

Traiter une action de l'utilisateur

Dans l'exemple Hello World, pour que le clic sur le bouton déclenche une action, il faut traiter l'événement associé.

La méthode setOnAction() du bouton permet d'enregistrer un Event Handler (c'est une interface fonctionnelle possédant la méthode handle(event) qui définit l'action à effectuer).

IHM-1 – FX03 – Jacques BAPST 9

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();

}

Page 10: Java FX Partie3

Propriétés

IHM-1 – FX03 – Jacques BAPST 10

Page 11: Java FX Partie3

Notion de propriété [1]

La notion de "propriété" (property) est très présente dans JavaFX.

Une propriété est un élément d'une classe que l'on peut manipulerà l'aide de getters (lecture) et de setters (écriture).

Les propriétés sont généralement représentées par des attributs de la classe mais elles pourraient aussi être stockées dans une base de données ou autre système d'information.

En plus des méthodes get…() et set…(), les propriétés JavaFXpossèdent une troisième méthode …Property() qui retourne un objet qui implémente l'interface Property [… : nom de la propriété].

Intérêt des propriétés :• Elles peuvent être liées entre-elles (Binding), c-à-d que le changement

d'une propriété entraîne automatiquement la mise à jour d'une autre.

• Elles peuvent déclencher un événement lorsque leur valeur change et un gestionnaire d'événement (Listener) peut réagir en conséquence.

IHM-1 – FX03 – Jacques BAPST 11

Page 12: Java FX Partie3

Notion de propriété [2]

Exemple d'une classe définissant la propriété balance (solde) pour un compte bancaire.

IHM-1 – FX03 – Jacques BAPST 12

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;

}

. . .

}

Page 13: Java FX Partie3

Notion de propriété [3]

La classe abstraite DoubleProperty permet d'emballer une valeur de type double et d'offrir des méthodes pour consulter et modifier la valeur mais également pour "observer" et "lier" les changements.

SimpleDoubleProperty est une classe concrète prédéfinie.

La plateforme Java offre des classes similaires pour la plupart des types primitifs, les chaînes de caractères, certaines collections ainsi que le type Object qui peut couvrir tous les autres types.• IntegerProperty / SimpleIntegerProperty

• StringProperty / SimpleStringProperty

• ListProperty<E> / SimpleListProperty<E>

• ObjectProperty<T> / SimpleObjectProperty<T>

• . . .

Des classes existent également pour définir des propriétés read-only• ReadOnlyIntegerWrapper, ReadOnlyIntegerProperty

• . . .

IHM-1 – FX03 – Jacques BAPST 13

Page 14: Java FX Partie3

Observation des propriétés [1]

Toutes les classes de propriétés implémentent l'interface Observable et offrent de ce fait, la possibilité d'enregistrer des observateurs (Listener) qui seront avertis lorsque la valeur de la propriété change.

Une instance de l'interface fonctionnelle ChangeListener<T>pourra ainsi être créée pour réagir à un tel changement. La méthode changed() sera alors invoquée et recevra en paramètre la valeur observée ainsi que l'ancienne et la nouvelle valeur de la propriété.

IHM-1 – FX03 – Jacques BAPST 14

DoubleProperty sum = account.balanceProperty();

sum.addListener( (ObservableValue<? extends Number> obsVal,Number oldVal,Number newVal ) ->{

//--- ChangeListener codeSystem.out.println(oldVal+" becomes "+ newVal);. . .

} );

Page 15: Java FX Partie3

Observation des propriétés [2]

Remarque : Dans l'exemple précédent, une expression lambda est utilisée pour implémenter la méthode changed(). On pourrait également utiliser une classe anonyme ou créer l'instance d'une classe "ordinaire" qui implémente l'interface ChangeListener<T>.

L'interface fonctionnelle InvalidationListener<T> permet également de réagir aux changements des valeurs de propriétés dans les situations où les propriétés sont calculées à partir d'autres et que l'on veut éviter d'effectuer les calculs à chaque changement.

Avec cette interface, c'est la méthode invalidated(Observable o)qui est invoquée lorsqu'un changement potentiel de la valeur de la propriété est intervenu.

Cette méthode peut cependant être invoquée alors que le résultat observé n'a finalement pas changé (cela dépend des opérations effectuées).

IHM-1 – FX03 – Jacques BAPST 15

< <

<

Co

mp

lém

en

t

> >

>

Page 16: Java FX Partie3

Propriétés des composants

Les composants utilisés dans les interfaces graphiques (boutons, champs texte, cases à cocher, sliders, etc.) possèdent tous de nombreuses propriétés.

Pour chacun des composants, la documentation (Javadoc) décrit dans une des rubriques (Property Summary) la liste des propriétésde la classe concernée ainsi que celles qui sont héritées.

IHM-1 – FX03 – Jacques BAPST 16

Page 17: Java FX Partie3

Lier des propriétés [1]

Un des avantages des propriétés JavaFX est la possibilité de pouvoir les lier entre-elles. Ce mécanisme, appelé binding, permet de mettre à jour automatiquement une propriété en fonction d'une autre.

Dans les interfaces utilisateurs, on a fréquemment ce type de liens.

• Par exemple, lorsqu'on déplace le curseurd'un slider, la valeur d'un champ textechangera (ou la luminosité d'une image,la taille d'un graphique, le niveau sonore,etc.).

Il est possible de lier deux propriétés Aet B de manière• Unidirectionnelle : un changement de A entraînera un changement

de B mais pas l'inverse (B non modifiable autrement)

• Bidirectionnelle : un changement de A entraînera un changementde B et réciproquement (les deux sont modifiables)

IHM-1 – FX03 – Jacques BAPST 17

Page 18: Java FX Partie3

Lier des propriétés [2]

Illustration des liens possibles entre deux propriétés A et B :

IHM-1 – FX03 – Jacques BAPST 18

A

B

B.bind(A)

A

B

B.bindBidirectional(A)ou

A.bindBidirectional(B)

Liaison unidirectionnelle

(la valeur de la propriété B dépend de la valeur de la

propriété A)

Liaison bidirectionnelle

(la valeur de la propriété B dépend de la valeur de la

propriété A et inversement)

Page 19: Java FX Partie3

Lier des propriétés [3]

La méthode bind() permet de créer un lien unidirectionnel.

La méthode doit être appelée sur la propriété qui sera "soumise" à l'autre (celle qui est passée en paramètre).

Dans cet exemple la valeur du solde du compte bancaire est liée (asservie) à la position du curseur du slider. Si l'on tente de modifier le solde d'une autre manière (avec setBalance() par exemple) une exception sera générée.

Une liaison bidirectionnelle s'effectue de manière similaire, mais en utilisant la méthode bindBidirectional().

Pour supprimer le lien : unbind() et unbindBidirectional()

IHM-1 – FX03 – Jacques BAPST 19

BankAccount account = new BankAccount();

Slider slider = new Slider();

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

Page 20: Java FX Partie3

Lier des propriétés [4]

Une propriété ne peut être liée (asservie) qu'à une seule autre si le lien est unidirectionnel (bind()). Par contre, les liens bidirectionnels (bindBidirectional()) peuvent être multiples.

Parfois, une propriété dépend d'une autre mais avec une relation plus complexe. Il est ainsi possible de créer des propriétés calculées.

Deux techniques sont à disposition (elles peuvent être combinées) :

• Utiliser la classe utilitaire Bindings qui possède de nombreuses méthodes statiques permettant d'effectuer des opérations.

• Utiliser les méthodes disponibles dans les classes qui représententles propriétés; ces méthodes peuvent être chaînées (Fluent API).

Des opérations de conversions sont parfois nécessaires si le type des propriétés à lier n'est pas le même. Par exemple pour lier un champ texte (StringProperty) à un slider dont la valeur est numérique (DoubleProperty).

IHM-1 – FX03 – Jacques BAPST 20

Page 21: Java FX Partie3

Lier des propriétés [5]

Exemple de binding permettant de coupler la valeur d'un slider(Area) aux valeurs d'entrée de deux autres sliders (Width et Height)

En utilisant les méthodes statiques de la classe Bindings :

IHM-1 – FX03 – Jacques BAPST 21

Slider widthSlider = new Slider(); // InputSlider heightSlider = new Slider(); // InputSlider areaSlider = new Slider(); // Ouput

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

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

Height SliderWidth Slider

Area Slider(produit des 2 valeurs)

Devient non éditablecar lié aux deux autres

Page 22: Java FX Partie3

Lier des propriétés [6]

Même exemple, en utilisant des méthodes chaînées (Fluent API) :

Un jeu d'opérations est disponible aussi bien avec la classe Bindingsqu'avec les méthodes chaînables.• min(), max()

• equal(), notEqual(), lessThan(), lessThanOrEqual(), …

• isNull(), isNotNull(), isEmpty(), isNotEmpty()

• convert(), concat(), format(), …

• et beaucoup d'autres . . .

IHM-1 – FX03 – Jacques BAPST 22

Slider widthSlider = new Slider(); // InputSlider heightSlider = new Slider(); // InputSlider areaSlider = new Slider(); // Ouput

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

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

Page 23: Java FX Partie3

Lier des propriétés [7]

Si les opérations disponibles dans les API, dites de haut-niveau, ne permettent pas d'exprimer la relation entre les propriétés, il est possible de définir une liaison de plus bas niveau (low-level binding) en redéfinissant la méthode abstraite computeValue() d'une des classes de binding (DoubleBinding, BooleanBinding, StringBinding, …).

IHM-1 – FX03 – Jacques BAPST 23

DoubleBinding complexBinding = new DoubleBinding() {{ //--- Set listeners to 'in'-properties

super.bind(aSlider.valueProperty(), bSlider.valueProperty());}

@Override //--- Compute 'out' valueprotected double computeValue() {

double w = aSlider.valueProperty().get();double h = bSlider.valueProperty().get();return Math.sqrt(h) * Math.pow(w, 3);

}};

outSlider.valueProperty().bind(complexBinding); // Do the binding

Page 24: Java FX Partie3

Architecture JavaFXConcepts techniques

IHM-1 – FX03 – Jacques BAPST 24

Page 25: Java FX Partie3

Architecture technique [1]

L'architecture technique de la plateforme JavaFX est composée de plusieurs couches (library stack) qui reposent sur la machine virtuelle Java (JVM).

Les développeurs ne devrait utiliser que la couche (API) publique car les couches inférieures sont susceptibles de subir des changements importants au fil des versions (sans aucune garantie de compatibilité).

Les "briques" intermédiaires ne seront donc pas décrites dans ce cours.

IHM-1 – FX03 – Jacques BAPST 25

Native Layer

Private Layer

Public Layer

Applications JavaFX

Page 26: Java FX Partie3

Éléments d'une application

Structure générale d'uneapplication JavaFX.

IHM-1 – FX03 – Jacques BAPST 26

Stage Scene

ContainerLayout

ComponentControl

ContainerLayout

ComponentControl

ComponentControl

ComponentControl

ComponentControl

. . . . . .

Graphe de scène(défini en Java ou avec FXML)

ComponentControl

. . .

. . .

ContainerLayout

. . .

Page 27: Java FX Partie3

Graphe de scène [1]

IHM-1 – FX03 – Jacques BAPST 27

Le graphe de scène (scene graph) est une notion importante qui représente la structure hiérarchique de l'interface graphique.

Techniquement, c'est un graphe acyclique orienté (arbre orienté) avec :• une racine (root)

• des nœuds (nodes)

• des arcs qui représentent les relations parent-enfant

Les nœuds (nodes) peuvent êtrede trois types :• Racine

• Nœud intermédiaire

• Feuille (leaf)

Page 28: Java FX Partie3

Graphe de scène [2]

IHM-1 – FX03 – Jacques BAPST 28

Les feuilles de l'arbre sont généralement constitués de composants visibles (boutons, champs texte, …) et les nœuds intermédiaires (y compris la racine) sont généralement des éléments de structuration (souvent invisibles), typiquement des conteneurs ou panneaux de différents types (HBox, VBox, BorderPane, …).

Page 29: Java FX Partie3

Graphe de scène [3]

IHM-1 – FX03 – Jacques BAPST 29

Tous les éléments contenus dans un graphe de scène sont des objets qui ont pour classe parente la classe Node.

La classe Node comporte de nombreuses sous-classes :

Simplifié !(il y a des classes intermédiaires)

Conteneurs (Layout-Panes) non représentés

(voir plus loin)

Page 30: Java FX Partie3

Graphe de scène [4]

IHM-1 – FX03 – Jacques BAPST 30

Parmi les sous-classes de Node on distingue différentes familles :

• Les formes primitives (Shape) 2D et 3D Line, Circle, Rectangle, Box, Cylinder, …

• Les conteneurs (Layout-Pane) qui se chargentde la disposition (layout) des composants enfantset 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 spécialisés qui sont dédiés àun domaine particulier (par exemple : lecteurmultimédia, navigateur web, etc.). MediaView, WebView, ImageView, Canvas, Chart, …

Page 31: Java FX Partie3

Conteneurs

IHM-1 – FX03 – Jacques BAPST 31

Les conteneurs (Layout-Pane) représentent une famille importante parmi les sous-classes de Node. Ils ont pour classe parente Pane et Region qui possèdent de nombreuses propriétés et méthodes héritées par tous les conteneurs.

. . .

Page 32: Java FX Partie3

Region - Structure visuelle [1]

IHM-1 – FX03 – Jacques BAPST 32

La classe Region est la classe parente des composants (Controls) et des conteneurs (Layout-Panes).

Elle définit des propriétés qui affectent la représentation visuelle.

Les différentes zones d'une région sont basées sur la spécificationdu Box-Model CSS3 (selon normalisation du W3C).

• Elles définissent les notions Margin, Border, Padding, Insets, Content

Les zones Border et Padding définissent les Insets (encarts)

de la région

Les composants enfants sont ajoutés dans la zone Content

Page 33: Java FX Partie3

Region - Structure visuelle [2]

IHM-1 – FX03 – Jacques BAPST 33

Comme la classe Region est la classe parente de tous les conteneurs et de tous les composants, ses propriétés sont héritées et peuvent s'appliquer à une grande variété d'éléments qui sont utilisés pour créer les interfaces.

Parmi ces propriétés, on peut mentionner :

• border

Bordure autour de la région

• background

Couleur ou image d'arrière-plan de la région

• padding

Marge (espace) autour du contenu de la région

L'utilisation et le codage des propriétés border et background sont expliqués plus en détail dans le chapitre suivant consacré aux conteneurs et layout-panes (à la section Disposition des composants -Généralités).

Page 34: Java FX Partie3

Style – Look and Feel [1]

La notion de style, skin, thème ou look and feel (L&F) caractérise l'ensemble des aspects visuels de l'interface graphique et de ses composants (forme, couleur, texture, ombre, police de caractères, …).

En JavaFX, le style des composants est défini 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 méthode setUserAgentStylesheet() de la classe Applicationpermet d'indiquer l'URL de la feuille de style qui est à appliquer globalement.

Deux styles, nommés Modena et Caspian, sont prédéfinis et sont associés aux constantes :• STYLESHEET_MODENA : Utilisé par défaut depuis JavaFX 8

• STYLESHEET_CASPIAN : A été défini pour JavaFX 2

IHM-1 – FX03 – Jacques BAPST 34

Page 35: Java FX Partie3

Style – Look and Feel [2]

Style Modena sur différents OS.

IHM-1 – FX03 – Jacques BAPST 35

Page 36: Java FX Partie3

Style – Look and Feel [3]

Le style utilisé par défaut 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 démarrage de l'application :

Des styles externes (third-party) peuvent également être importés et appliqués. On trouve différentes réalisations, par exemple :• Apple Aqua (AquaFX)

• Microsoft Modern UI (JMetro) Windows-7 Aero (AeroFX)

• Twitter Bootstrap (Fextile)

• Flatter (Embedded UI), . . .

IHM-1 – FX03 – Jacques BAPST 36

@Overridepublic void start(Stage primaryStage) {. . .setUserAgentStylesheet(STYLESHEET_CASPIAN);. . .