I. Quelques mots du traducteur

Cet article est la traduction française du tutoriel JavaFX de Sun que vous pouvez retrouver à l'adresse suivante : http://java.sun.com/javafx/1/tutorials/core/.

Lorsque j'étais à Devoxx 2008, j'ai rencontré Aaron Houston, qui est la personne de contact entre les Java-Champions et Sun, ainsi que Joshua Marinacci, responsable pour les démos JavaFX.

Ceux-ci m'ont donné l'autorisation de traduire en français les tutoriels concernant JavaFX.

Je ne peux que leur dire merci.

II. Pour commencer

II-A. Téléchargement et installation du JDK

Le langage de programmation JavaFX Script est basé sur la plateforme de développement et de ce fait requiert que le JDK 5 ou JDK 6 (cette version est plus rapide) soit installé sur votre système.

Si vous ne l'avez pas encore fait, téléchargez et installez le JDK 6 ou le JDK 5 maintenant, avant de continuer dans ce tutoriel.

II-B. Choix d'un environnement de développement

Lorsque vient le moment de choisir un environnement de développement, deux possibilités s'offrent à vous : utiliser un EDI (Environnement de Développement Intégré) ou un simple éditeur de texte. Cette décision est entièrement une question de goût, mais le résumé qui suit vous aidera dans votre choix.

  • Un EDI fournit un environnement de développement entièrement intégré. Vous téléchargez un logiciel complet, ou un plug-in à ce logiciel, qui vous fournit tout ce qu'il faut pour compiler/déboguer/exécuter vos applications. Les EDI présentent les fonctions les plus couramment utilisées en tant qu'éléments de GUI (Graphical User Interface ou Interface Utilisateur Graphique) et offrent tout un tas de fonctionnalités fort utiles comme la complétion de code automatique. Un IDE vous donne également un feedback immédiat sur les erreurs et une coloration syntaxique ce qui rend le code plus compréhensible.
  • Un éditeur de texte est simple et familier. Les programmeurs expérimentés aiment bien rester avec leur éditeur de texte de choix, préférant travailler dans cet environnement lorsque c'est possible (certains éditeurs comme vi ont des raccourcis clavier dont certains programmeurs ne peuvent se passer).

L'EDI supporté officiellement pour le langage de développement JavaFX Script est NetBeans 6.5. Le site Web de NetBeans fournit les instructions pour le télécharger, l'installer et le configurer.

II-C. Télécharger et installer le compilateur et le runtime JavaFX

Vous avez également besoin de télécharger et installer le compilateur et le runtime JavaFx. Une façon d'obtenir ce logiciel est de télécharger le SDK JavaFX dans son entièreté, ce qui vous donne le compilateur, le runtime et tout un tas d'autres outils.

Une autre façon est de simplement télécharger le dernier compilateur sous forme binaire depuis le site du projet OpenJFX. Le compilateur est lui-même écrit en Java. L'installation du binaire précompilé devient donc une façon d'extraire le fichier téléchargé et d'ajouter les outils javafxc et javafx dans votre path. Les instructions complètes pour cette approche peuvent être trouvées sur le wiki PlanetJFX.

Finalement, si vous désirez vraiment vous investir, vous pouvez rejoindre le projet OpenJFX Compiler, créez votre propre copie du compilateur et de compiler vous-même depuis les codes source du compilateur (si vous choisissez également cette approche, vous aurez besoin de la version 1.7.0 de Apache Ant, ainsi que d'une version récente de SubVersion, version 1.5.4 au moment de l'écriture de cet article). Pour plus d'informations sur la compilation du compilateur depuis ses sources, voir le wiki de PlanetJFX.

III. L'écriture de Scripts

Maintenant que votre environnement est prêt, il est temps d'écrire votre premier script !
Dans cette leçon, nous allons explorer quelques bases de programmation en écrivant une très simple application de calcul. Cette approche va vous familiariser avec :

  • la compilation du code source ;
  • l'exécution de l'application ;
  • la déclaration des variables de script ;
  • la définition et l'invocation de fonctions de script ;
  • le passage d'arguments aux fonctions de script ;
  • l'accès aux arguments de la ligne de commande.

III-A. Écriture d'une simple calculatrice

Pour commencer, cliquez sur calculatrice.fx et enregistrez le fichier.
Vous devriez obtenir le code suivant :

 
Sélectionnez
def nombreUn = 100;
def nombreDeux = 2;
var resultat;

addition();
soustraction();
multiplication();
division();

function addition() {
     resultat = nombreUn + nombreDeux;
     println("{nombreUn} + {nombreDeux} = {resultat}");
}

function soustraction() {
     resultat = nombreUn - nombreDeux;
     println("{nombreUn} - {nombreDeux} = {resultat}");
}

function multiplication() {
     result = nombreUn * nombreDeux;
     println("{nombreUn} * {nombreDeux} = {resultat}");
}

function division() {
     resultat = nombreUn / nombreDeux;
     println("{nombreUn} / {nombreDeux} = {resultat}");
}

Le langage de programmation JavaFX Script est un langage compilé, ce qui signifie que tout code source que vous écrivez doit d'abord être converti en Java ByteCode (le langage de la Machine Virtuelle Java) avant de l'exécuter sur votre système.

La commande suivante va compiler le script de la calculatrice :

 
Sélectionnez
javafxc calculatrice.fx

Après la compilation, vous noterez que le ByteCode Java correspondant aura été généré et placé dans un fichier nommé calculatrice.class.

Vous noterez qu'un autre fichier, calculatrice$Intf.class est également créé. Ce fichier est nécessaire pour exécuter l'application (vous pouvez l'ignorer, mais pas le supprimer).

Vous pouvez maintenant exécuter la classe compilée (dans la Machine Virtuelle Java) avec la commande suivante :

 
Sélectionnez
javafx calculatrice

Le résultat sera :

 
Sélectionnez
100 + 2 = 102
100 - 2 = 98
100 * 2 = 200
100 / 2 = 50

Cette application peut sembler petite, mais elle vous familiarise avec des concepts importants du langage de programmation.
Apprendre ces concepts est votre passage obligé pour maîtriser le langage de programmation JavaFX Script.

Le langage de programmation JavaFX Script n'est pas difficile à apprendre. Mais vu que c'est votre première confrontation à ce langage, nous allons détailler les nouveaux concepts de façon suffisante pour que vous puissiez prendre en main l'application.
Notre but, dans cette approche, est la clarté. Nous discuterons de façon plus détaillée dans les leçons suivantes si nécessaire.

III-B. Déclaration des variables de script

Jetons un œil sur l'exemple calculatrice.fx - plus tard, nous allons étendre cet exemple.

 
Sélectionnez
def nombreUn = 100;
def nombreDeux = 2;
var resultat;

Les variables de script sont déclarées à l'aide des mots-clés def ou var.
La différence entre les deux est que les variables var peuvent recevoir de nouvelles valeurs durant leur cycle de vie, alors que les variables def restent constantes une fois initialisées. Nous avons assigné des valeurs à nombreUn et nombreDeux, mais n'avons pas initialisé la variable resultat parce que cette variable va accueillir le résultat de nos calculs.

Les noms de variables consistent en général en des lettres et des chiffres, bien qu'ils ne peuvent commencer par des chiffres. La convention est d'utiliser des lettres en minuscule. Si le nom est composé de plus d'un mot, la première lettre des mots suivants sera mise en majuscule, comme illustré dans l'exemple précédent.

Vous aurez également remarqué que nous n'avons rien fait de spécial pour indiquer que ces variables allaient accueillir des nombres (à opposer aux chaînes de caractères ou tout autre type de données).
Le compilateur est suffisamment malin pour connaître vos intentions en se basant sur le contexte dans lequel la variable est utilisée. Cela s'appelle l'inférence de type. L'inférence de type facilite un petit peu votre travail de programmeur puisqu'il vous libère de cette corvée de devoir toujours définir les types de données que pourra accueillir votre variable.

III-C. Définitions et invocation de fonctions de script

Le restant du code source défini des fonctions de script qui additionne, soustrait, multiplie et divise les deux nombres :

 
Sélectionnez
function addition() {
     resultat = nombreUn + nombreDeux;
     println("{nombreUn} + {nombreDeux} = {resultat}");
}

function soustraction() {
     resultat = nombreUn - nombreDeux;
     println("{nombreUn} - {nombreDeux} = {resultat}");
}

function multiplication() {
     result = nombreUn * nombreDeux;
     println("{nombreUn} * {nombreDeux} = {resultat}");
}

function division() {
     resultat = nombreUn / nombreDeux;
     println("{nombreUn} / {nombreDeux} = {resultat}");
}

Une fonction est un bloc de code exécutable qui effectue une tâche particulière. Dans notre exemple, chaque fonction effectue une opération mathématique et affiche le résultat.
L'organisation du code en fonction est une pratique courante qui simplifie la lecture de votre programme, son utilisation et son débogage. Le corps d'une fonction sera indenté, permettant de voir plus facilement où commence et termine une fonction.

Le code d'une fonction ne s'exécute que lorsque la fonction est explicitement invoquée. Cela permet d'exécuter une fonction depuis n'importe quel endroit de votre script. Cela importe peu que votre invocation de fonction soit placée avant ou après la définition de la fonction. Dans notre exemple, nous invoquons les fonctions avant qu'elles ne soient définies.

Les invocations de fonctions sont les suivantes :

 
Sélectionnez
add();
subtract();
multiply();
divide();

III-D. Passer des arguments aux fonctions

Nous allons maintenant modifier nos fonctions de script de calculatrice pour accepter des arguments. Des arguments sont des valeurs spécifiques que vous passez lorsque vous invoquez une fonction. Avec cette approche, notre calculatrice peut effectuer des calculs sur n'importe quel nombre, pas uniquement sur des valeurs fixes dans les variables nombreUn et nombreDeux.

 
Sélectionnez
var result;

addition(100,10);
soustraction(50,5);
multiplication(25,4);
division(500,2);

function addition(argumentUn: Integer, argumentDeux: Integer) {
     resultat = argumentUn + argumentDeux;
     println("{argumentUn} + {argumentDeux} = {resultat}");
}

function soustraction(argumentUn: Integer, argumentDeux: Integer) {
     resultat = argumentUn - argumentDeux;
     println("{argumentUn} - {argumentDeux} = {resultat}");
}

function multiplication(argumentUn: Integer, argumentDeux: Integer) {
     resultat = argumentUn * argumentDeux;
     println("{argumentUn} * {argumentDeux} = {resultat}");
}

function division(argumentUn: Integer, argumentDeux: Integer) {
     resultat = argumentUn / argumentDeux;
     println("{argumentUn} / {argumentDeux} = {resultat}");
}

Le résultat de ce script est maintenant :

 
Sélectionnez
100 + 10 = 110
50 - 5 = 45
25 * 4 = 100
500 / 2 = 250

Dans cette version, nous avons supprimé les variables nombreUn et nombreDeux puisqu'elles ne sont plus nécessaires.
Au lieu de cela, nous avons modifié les définitions de fonction pour qu'elles acceptent que deux nombres soient passés en argument.
Chaque argument spécifie son nom, suivi de deux points (:), suivi de son type. Lorsqu'une fonction accepte plusieurs arguments, ils sont séparés par une virgule.

III-E. Retourner des valeurs d'une fonction de script

Une fonction peut retourner, optionnellement, une valeur au code qui l'a invoqué. Par exemple, la fonction addition peut être modifiée pour retourner le résultat.

 
Sélectionnez
function addition(argumentUn: Integer, argumentDeux: Integer) : Integer {
     resultat = argumentUn + argumentDeux;
     println("{argumentUn} + {argumentDeux} = {resultat}");
     return resultat;
}

La fonction addition peut maintenant être invoquée comme suit :

 
Sélectionnez
var total;

total = addition(1,300) + addition(23,52);

Si aucune valeur de retour n'est spécifiée, la fonction retourne Void par défaut.

III-F. Accéder aux arguments de ligne de commande

Nous allons modifier le script calculatrice pour accepter des arguments en ligne de commande. Cela permet aux utilisateurs finaux de spécifier les nombres à calculer à l'exécution.

 
Sélectionnez
var result;

function run(args : String[]) {

     // Convertion de Strings en Entiers
     def nombreUn = java.lang.Integer.parseInt(args[0]);
     def nombreDeux = java.lang.Integer.parseInt(args[1]);

     // Invocation des Fonctions 
     addition(nombreUn,nombreDeux);
     soustraction(nombreUn,nombreDeux);
     mutiplication(nombreUn,nombreDeux);
     division(nombreUn,nombreDeux);
}

function addition(argumentUn: Integer, argumentDeux: Integer) {
     resultat = argumentUn + argumentDeux;
     println("{argumentUn} + {argumentDeux} = {resultat}");
}

function soustraction(argumentUn: Integer, argumentDeux: Integer) {
     resultat = argumentUn - argumentDeux;
     println("{argumentUn} - {argumentDeux} = {resultat}");
}

function multiplication(argumentUn: Integer, argumentDeux: Integer) {
     resultat = argumentUn * argumentDeux;
     println("{argumentUn} * {argumentDeux} = {resultat}");
}

function division(argumentUn: Integer, argumentDeux: Integer) {
     resultat = argumentUn / argumentDeux;
     println("{argumentUn} / {argumentDeux} = {resultat}");
}

Cette modification introduit quelques nouveaux concepts, dont l'ajout de la fonction run(). Contrairement à nos autres fonctions, la fonction run() est une fonction spéciale qui sert de point d'entrée principal au script. La fonction run() stoque tous les arguments en ligne de commande dans args, qui est une séquence d'objets String (les séquences sont des listes ordonnées d'objets, similaires aux tableaux dans d'autres langages de programmation. Elles sont expliquées en détails dans Expressions et Opérations).

Pour exécuter ce script, l'utilisateur doit maintenant spécifier le premier et second paramètre à l'exécution :

 
Sélectionnez
javafx calculatrice 100 50

Le résultat est maintenant :

 
Sélectionnez
100 + 50 = 150
100 - 50 = 50
100 * 50 = 5000
100 / 50 = 2

Dans les versions précédentes du script calculatrice, nous n'avions pas spécifié de fonction run(). Nous avons juste tapé le code à exécuter au niveau du script et il s'est exécuté comme espéré. Dans ces cas-là, le compilateur génère silencieusement une fonction run() sans argument et place le code à exécuter à l'intérieur de celle-ci.

Nous avons également réintroduit les variables nombreUn et nombreDeux, cette fois-ci en limitant leur portée à la fonction run() qui les contient. Nos fonctions de calculatrice espèrent des nombres entiers, mais les arguments en ligne de commande sont des String. Il nous faut pour cela convertir chaque argument en ligne de commande de String en Integer avant de pouvoir les passer aux fonctions.

 
Sélectionnez
// Convertion de Strings en Entiers
def nombreUn = java.lang.Integer.parseInt(args[0]);
def nombreDeux = java.lang.Integer.parseInt(args[1]);

Pour cela, nous nous sommes aidés du langage de programmation Java pour exécuter ce type de conversion. Puiser dans l'écosystème Java existant lorsque nécessaire apporte une puissance phénoménale à ce langage de script.

IV. L'Utilsation d'objets

Qu'est ce qu'un objet en JavaFX ? Comment en créer un ? Cette leçon vous introduit aux concepts de base des objets, littéraux d'objets, et comment invoquer une fonction d'un objet.

IV-A. Qu'est ce qu'un objet ?

Que sont des objets ? Les objets sont des bouts de logiciels qui possèdent des états et des comportements. En gros :

  • l'état d'un objet est représenté par ses variables ;
  • le comportement d'un objet est représenté par ses fonctions.

Conceptuellement, un objet peut modéliser à peu près tout, que ce soient des composants GUI (boutons, labels, cases à cocher) ou des abstractions non visuelles (température, distance, etc.).

Pour plus d'informations, veuillez vous référer à la leçon qu'est ce qu'un objet dans les tutoriels Java.

IV-B. Déclaration d'un littéral d'objet

Dans le langage de programmation JavaFX, un objet est créé avec un littéral d'objet :

 
Sélectionnez
Adresse {
   rue: "1 Main Street";
   ville: "Santa Clara":
   etat: "CA";
   codePostal:"95050";
   pays:"USA";
}

Ici, nous avons créé un objet Adresse, pour être utilisé dans une hypothétique application de carnet d'adresse. Téléchargez Adresse.zip et décompressez deux fichiers .class et CarnetAdresse.fx.

Les fichiers Adresse.class (Adresse.class et Adresse$Intf.class) contiennent des informations dont le compilateur a besoin avant que vous puissiez créer des objets Adresse. Si vous désirez savoir d'où cela provient, nous avons tout d'abord créé une définition de classe Adresse (dans un fichier Adresse.fx) et l'avons ensuite compilé, ce qui a produit les classes Adresse.class et Adresse$Intf.class)
Le langage de programmation JavaFX Script -- et le langage de programmation Java sur lequel il se repose -- fournit un large nombre de fichiers .class à utiliser dans vos programmes. Cela permet de créer des objets pour un large éventail de tâches de programmation, y compris le développement de GUI avec des effets visuels sophistiqués. Nous décrivons comment écrire vos propres classes à la fin de ce tutoriel, dans « Écriture de vos propres classes ». Entre temps, nous vous demanderons de télécharger un ou deux fichiers .class pour des exemples spécifiques comme celui-ci.

Maintenant, compiler le script :

 
Sélectionnez
javafxc CarnetAdresse.fx

Rien dans ce code ne produit de résultat, mais le fait qu'il compile est une preuve que la création d'objet est un succès.

Techniquement parlant, les variables dans cet exemple sont appelées variables d'instance. Vous pouvez vous représenter des variables d'instance comme l'ensemble d'attributs que chaque objet contient. Dans les faits, le terme « attribut » était utilisé dans des versions précédentes du langage (vous pourriez le rencontrer occasionnellement dans de précédentes démonstrations et documentations). Dans le monde de la programmation orientée objet, les termes « instances » et « objet » sont synonymes.

IV-C. Syntaxe d'un littéral d'objet

La syntaxe d'un littéral d'objet est aussi bien simple qu'intuitif à utiliser. Le premier mot Adresse spécifie le type d'objet que vous créez. Les accolades d'ouverture et de fermeture définissent le corps de l'objet. Tout le reste (rue, ville, etat, codePostal, pays) initialise les variables d'instance d'objets.

De multiples objets peuvent être créés de manière suivante :

 
Sélectionnez
Adresse {
     rue: "1 Main Street";
     ville: "Santa Clara";
     etat: "CA";
     codePostal: "95050";
     pays:"USA";
}

Adresse {
     rue: "200 Pine Street";
     ville: "San Francisco";
     etat: "CA";
     codePostal: "94101";
     pays:"USA";
}

Lorsque vous déclarez un littéral d'objet, les variables d'instance peuvent être séparées par des virgules ou des espaces, aussi bien que des point-virgules. La déclaration suivante est donc également correcte :

 
Sélectionnez
Adresse {
     rue: "1 Main Street",
     ville: "Santa Clara",
     etat: "CA",
     codePostal: "95050",
     pays:"USA",
}

Adresse {
     rue: "200 Pine Street"
     ville: "San Francisco"
     etat: "CA"
     codePostal: "94101"
     pays:"USA"
}

Ce tutoriel utilise généralement les point-virgules.
Les point-virgules sont requis pour la déclaration de fonction.

Vous pouvez également assigner les objets nouvellement créés à des variables pour un accès ultérieur :

 
Sélectionnez
def adresseUne = Adresse {
     rue: "1 Main Street",
     ville: "Santa Clara",
     etat: "CA",
     codePostal: "95050",
     pays:"USA",
}

def adresseDeux = Adresse {
     rue: "200 Pine Street"
     ville: "San Francisco"
     etat: "CA"
     codePostal: "94101"
     pays:"USA"
}

Vous pouvez également inclure la définition d'un objet dans un autre objet :

 
Sélectionnez
def client = Client {
     prenom: "John";
     nom: "Doe";
     telephonne: "(408) 555-1212";
     adresse: Adresse {
          rue: "1 Main Street";
          ville: "Santa Clara";
          etat: "CA";
          codePostal: "95050";
          pays:"USA";
     }
}

Dans ce dernier exemple, l'objet Client introduit quelques variables et contient l'objet Adresse dans la variable nommée adresse. Cette structure d'objet imbriqué est très courante et démontre comment le programmeur (ou l'EDI) indente le corps lorsqu'un objet contient un autre.
De part son indentation, la variable adresse devient visuellement séparée de la variable client. Pour compiler cet exemple, téléchargez Client.zip, décompressez-la et placez les fichiers dans le même répertoire que les autres, puis compilez vos scripts comme d'habitude.

IV-D. Invocation des fonctions d'instance

Il y a plusieurs classes disponibles dans JavaFX qui fournissent le comportement dont vous désirez tirer avantage. Ce comportement est accessible via les fonctions d'objet. Vous apprendrez comment écrire des fonctions pour vos objets dans « Écriture de vos propres classes », mais maintenant, nous allons vous montrer comment utiliser des comportements existants.

Vous pouvez invoquer les fonctions d'instance d'un objet en tapant le nom de la variable (client dans ce cas) suivi d'un point ("."), suivi de la fonction que vous désirez invoquer.

 
Sélectionnez
def client = Client {
     prenom: "John";
     nom: "Doe";
     telephonne: "(408) 555-1212";
     adresse: Adresse {
          rue: "1 Main Street";
          ville: "Santa Clara";
          etat: "CA";
          codePostal: "95050";
          pays:"USA";
     }
}
client.afficheNom();
client.afficheTelephone();
client.afficheAdresse();

Cela affichera le résultat suivant :

 
Sélectionnez
Nom: John Doe
Telephone: (408) 555-1212
Rue: 1 Main Street
Ville: Santa Clara
Etat: CA
CodePostal: 95050
Pays: USA

Maintenant, vous vous demandez très certainement : « d'où viennent ces fonctions ? Comment puis-je savoir quelles variables d'instance ou fonction un objet contient ? ». Si vous désirez utiliser une bibliothèque de classes ou une classe, vous devez consulter la documentation de son API (Application Programming Interface).
La documentation de l'API est une liste formelle de variables d'objets et de fonctions.
Sa consultation est la seule façon de savoir assurément quelle fonctionnalité un objet donné va fournir.
Vous apprendrez comment utiliser cette documentation dans d'autres tutoriels, lorsque vous apprendrez à concevoir des applications graphiques.

V. Types de données

Nous avons vu quelques exemples de types d'objet : Adresse et Client. Les types String, Number, Integer, Boolean et Duration sont également des types d'objet. Ces types seront discutés dans cette leçon. Cette leçon discute également des types Void et null.

V-A. String

Vous avez déjà vu pas mal d'exemples de String, mais voyons quelques détails supplémentaires. Une String peut être déclarée en utilisant soit des simples soit des doubles guillemets.

 
Sélectionnez
var s1 = 'Hello';
var s2 = "Hello";

Les simples et doubles guillemets sont symétriques : vous pouvez imbriquer des simples guillemets dans des doubles guillemets ou imbriquer des doubles guillemets dans des simples guillemets.

Vous pouvez également inclure des expressions dans des String en utilisant les accolades {} :

 
Sélectionnez
def nom = 'Joe';
var s = "Bonjour {nom}"; // s = 'Bonjour Joe'

L'expression incluse dans la String peut à son tour contenir des String, qui à leur tour peuvent contenir des expressions :

 
Sélectionnez
def reponse = true;
var s = "La reponse est {if (reponse) "Oui" else "Non"}"; // s = 'La réponse est Oui'

À l'exécution, le compilateur va substituer l'expression {if (reponse) "Oui" else "Non"} par la String "Oui" si la valeur de reponse est true ou "Non" dans l'autre cas.

Pour joindre (concaténer) plusieurs Strings, utilisez les accolades à l'intérieur des guillemets :

 
Sélectionnez
def un = "Cet exemple ";
def deux = "joint deux chaines de caracteres.";
def trois = "{un}{deux}";      // joint la chaine de caractères un avec la chaine de caractères deux
println(trois);                // 'Cet exemple joint deux chaines de caracteres.'

V-B. Les types Number et Integer

Les types Number et Integer représentent des données numériques, bien que pour la plupart des tâches de script, vous laisserez le compilateur inférer le type correct  :

 
Sélectionnez
def nombreUn = 1.0; // compilateur va l'associer à Number 
def nombreDeux = 1;   // compilateur va l'associer à Integer

La différence entre ces deux types est que Number représente des nombres en virgules flottantes, mais Integer représente uniquement des entiers. Utilisez Number uniquement lorsque vous avez besoin d'une précision en virgule flottante.
Dans tous les autres cas, Integer devrait être votre premier choix.

V-C. IV-C. Boolean

Le type Boolean représente deux valeurs : true ou false. Utilisez ce type lorsque vous définissez un état :

 
Sélectionnez
var estEndormi = true;

Ou lors de l'évaluation d'une expression conditionnelle :

 
Sélectionnez
if (endormi) {
     reveillezVous();
}

Si l'expression indiquée entre parenthèses "()" est vraie, le code inclut entre les accolades "{}" est exécuté.
Pour plus d'informations sur les expressions conditionnelles, veuillez voir la section « Expression ».

V-D. Duration

Le type Duration représente une unité fixe de temps (millisecondes, secondes, minutes, heures) :

 
Sélectionnez
5ms; // 5 millisecondes
10s; // 10 secondes
30m; // 30 minutes
1h; // 1 heure

Les durées sont suffixées d'unités de temps. Les durées sont généralement utilisées dans les animations (que vous découvrirez dans la leçon « Création d'objets animés" » du tutoriel « Concevoir des Applications GUI avec JavaFX »).

V-E. Void

Void est utilisé pour indiquer que la fonction ne retourne pas de valeur.

 
Sélectionnez
function printMe() : Void {
 println("Je ne retourne rien");
}

C'est équivalent au code suivant, qui omet le type de retour de la fonction :

 
Sélectionnez
function printMe(){
 println("Je ne retourne rien");
}

Le mot clef Void en JavaFX commence par un V en majuscule. Si vous êtes familier avec le mot clef void du langage de programmation Java, vous devriez y faire attention.

En JavaFX, tout est expression. Le type de retour de la seconde fonction PrintMe est également Void, car le compilateur est capable d'inférer son type. Vous apprendrez plus à ce sujet dans la leçon « Expressions ».

V-F. null

null est une valeur spéciale utilisée pour indiquer une valeur normale manquante. null n'est pas la même chose que zéro ou une chaîne vide, donc comparer avec null n'est pas la même chose que comparer avec zéro ou une chaîne vide.

Le mot clé null permet de faire des comparaisons. Il est courant de voir null utilisé comme ceci :

 
Sélectionnez
function verification(arg1: Adresse) {
     if(arg1 == null) {
          println("J'ai recu un argument null.");
     } else {
          println("L'argument a une valeur.");
     }
}

Cette fonction accepte un argument et exécute un simple test pour vérifier si sa valeur est null.

VI. Séquences

Si vous avez une liste d'éléments, vous désirerez apprendre les séquences. Cette leçon vous montre comment créer, utiliser et comparer des séquences. Vous apprendrez également comment accéder à un sous-ensemble de séquence, appelé une part.

VI-A. La création de séquence

En plus des six éléments de bases, le langage de programmation JavaFX Script fournit également des structures de données, nommées séquences. Les séquences représentent des listes ordonnées d'objets. Les objets d'une séquence sont appelés éléments. Les séquences sont déclarées à l'aide d'accolades droites "[]" et chaque élément est séparé par une virgule.

Une façon de créer une séquence est d'explicitement lister ces éléments. Chaque élément est séparé par une virgule et la liste est entourée d'accolades droites "[" et "]". Par exemple, le code suivant :

 
Sélectionnez
var joursDeLaSemaine = ["Lun", "Mar", "Mer", "Jeu", "Ven"];

déclare une séquence et l'assigne à une variable nommée joursDeLaSemaine. Le compilateur sait que nous désirons créer une séquence de String car les éléments individuels sont tous de type String. Si la séquence avait été déclarée avec des entiers (par exemple, var nums=[1,2,3];), le compilateur devrait savoir que nous désirons une séquence d'Integer.

Vous pouvez également spécifier explicitement un type de séquence en modifiant sa déclaration de variable pour inclure le nom du type suivi de [].

 
Sélectionnez
var joursDeLaSemaine: String[] = ["Lun", "Mar", "Mer", "Jeu", "Ven"];

Cela indique au compilateur que la variable joursDeLaSemaine va accueillir une séquence de String (et non une simple String).

Les séquences peuvent également être déclarées dans d'autres séquences.

 
Sélectionnez
var jours = [joursDeLaSemaine, ["Sam", "Dim]];

Dans un tel cas, le compilateur va automatiquement « aplatir » les séquences imbriquées pour ne former qu'une seule séquence, rendant le code précédent équivalent à ceci :

 
Sélectionnez
var jours: String[] = ["Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim"];

Il existe également une notation abrégée qui simplifie la création de séquences qui forment une suite arithmétique. Pour créer une séquence constituée des nombres 1 à 100, utilisez ce qui suit :

 
Sélectionnez
var nums = [1..100];

VI-B. Création de séquences avec des expressions booléennes

Vous pouvez utiliser une expression booléenne ou un prédicat, pour déclarer une nouvelle séquence qui est un sous-ensemble d'une séquence existante. Considérez l'exemple suivant :

 
Sélectionnez
var nombres = [1,2,3,4,5];

Pour créer une seconde séquence (basée sur des éléments trouvés dans la première séquence) mais contenant seulement les nombres plus grand que 2, utilisez le code suivant :

 
Sélectionnez
var nombresPlusGrandsQueDeux = nombres[n | n > 2];

Vous pouvez exprimer la ligne de code précédente en français comme ceci : « sélectionner tous les éléments de la séquence nombres où la valeur d'un élément est plus grand que 2 et assigner ces éléments dans une nouvelle séquence nommée nombresPlusGrandsQueDeux ». La clause « où » est le prédicat.

Dans ce code :

  1. La séquence nouvellement créée est stockée dans une variable nommée nombresPlusGrandQueDeux ;
  2. Le code (maqué en vert) nombres[n | n > 2] spécifie la séquence originale d'où les éléments seront copiés. Dans notre exemple, nombres est le nom de la séquence existante ;
  3. Cela sélectionne les éléments de nombres et retourne une nouvelle séquence constituée des éléments, dans l'ordre, pour lesquels l'expression était vraie ;
  4. Le caractère "|" est utilisé pour visuellement séparer la variable n du restant du code : nombre[n | n > 2]; ;
  5. Le code (marqué en vert) nombres[n | n > 2]; définit une expression booléenne spécifiant le critère à remplir pour être repris dans la nouvelle séquence.

VI-C. Accéder aux éléments d'une séquence

Les éléments de séquence sont accessibles par ordre numérique, commençant par 0. Pour accéder à un élément individuel, indiquer le nom de la séquence suivi par le numéro d'ordre de l'élément, dans des accolades droites [] :

 
Sélectionnez
var jours = ["Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim"];

println(days[0]);
println(days[1]);
println(days[2]);
println(days[3]);
println(days[4]);
println(days[5]);
println(days[6]);

Ce qui affichera ce qui suit à l'écran :

 
Sélectionnez
Lun
Mar
Mer
Jeu
Ven
Sam
Dim

Vous pouvez également déterminer la taille d'une séquence en utilisant l'opérateur sizeof, suivi du nom de la séquence :

 
Sélectionnez
sizeof days

Le code suivant affiche 7 à l'écran.

 
Sélectionnez
var jours = ["Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim"];
println(sizeof jours);

VI-D. Insertion d'éléments dans une séquence

Le mot-clef insert vous permet d'insérer un élément dans une séquence, avant un élément spécifique ou après un élément spécifique.

En vérité, les séquences sont immuables. Ce qui signifie qu'une fois qu'elles sont créées, elles ne changent plus.
Lorsque vous modifiez une séquence, en insérant, ou supprimant des éléments par exemple, une nouvelle séquence est en fait créée et la variable de séquence est réassignée, donnant l'impression que la séquence a été modifiée.

Explorons cela en recréant la séquence jours :

 
Sélectionnez
var jours = ["Lun"];

À ce moment-là, la séquence contient seulement un élément : « Lun ».

Nous pouvons insérer « Mar » à la fin de cette séquence en utilisant les mots-clefs insert et into :

 
Sélectionnez
insert "Mar" into jours;

On peut également rajouter « Ven », « Sam », et « Dim » :

 
Sélectionnez
insert "Ven" into jours;
insert "Sam" into jours;
insert "Dim" into jours;

La séquence contient maintenant : « Lun », « Mar », « Ven », « Sam » et « Dim ».

Nous pouvons également utiliser les mots clefs insert et before pour insérer un élément avant un élément à une position donnée. N'oubliez pas que l'index commence à 0. Donc, dans notre séquence actuelle, « Ven » se situe à la position 2. De ce fait, pour insérer « Jeu » avant « Ven », il faut faire comme suit :

 
Sélectionnez
insert "Jeu" before jours[2];

La séquence contient maintenant « Lun », « Mar », « Jeu », « Ven », « Sam » et « Dim ».

Pour insérer « Mer » après « Mar », nous pouvons utiliser les mots-clefs insert et after.

 
Sélectionnez
insert "Mer" after jours[1];

La séquence contient maintenant tous les jours de la semaine : « Lun », « Mar », « Mer », « Jeu », « Ven », « Sam » et « Dim ».

VI-E. Suppression d'éléments d'une séquence

Les mots clefs delete et from facilite la suppression d'éléments d'une séquence :

 
Sélectionnez
delete "Dim" from jours;

La séquence contient maintenant « Lun », « Mar », « Mer », « Jeu », « Ven » et « Sam ».

Vous pouvez également supprimer un élément situé à une position donnée. Le code suivant supprime « Lun » de la séquence (souvenez-vous que « Lun » est le premier élément, son index est donc 0).

 
Sélectionnez
delete jours[0];

Pour effacer tous les éléments d'une séquence, utilisez le mot clef delete suivi du nom de la séquence :

 
Sélectionnez
delete jours;

Notez que delete enlève uniquement les éléments de la séquence. Il ne supprime pas la variable jours de votre script. Vous pouvez toujours accéder à la variable jours et y rajouter de nouveaux éléments comme auparavant.

VI-F. Inverser les éléments d'une Séquence

Vous pouvez facilement inverser les éléments d'une séquence en utilisant l'opérateur reverse.

 
Sélectionnez
var nombres = [1..5];
reverse nombres; // retourne [5, 4, 3, 2, 1]

VI-G. Comparaison des Séquences

Il y a des fois où vous pouvez désirer comparer des séquences pour leur égalité. Les séquences sont comparées pour égalités par valeur : si leurs longueurs sont égales et leurs éléments sont égaux, alors les séquences sont égales.

Testons cela en créant deux séquences ayant des contenus identiques :

 
Sélectionnez
var seq1 = [1, 2, 3, 4, 5];
var seq2 = [1, 2, 3, 4, 5];
println (seq1 == seq2);

L'expression seq1 == seq2 est évaluée à true parce que les deux séquences ont le même nombre d'éléments et la valeur de chacun des éléments est la même dans les deux séquences. Ce code affiche donc true à l'écran.

En changeant le nombre d'éléments dans une séquence (mais pas dans l'autre), les séquences sont maintenant de longueurs différentes :

 
Sélectionnez
var seq1 = [1, 2, 3, 4, 5];
var seq2 = [1, 2, 3, 4, 5, 6];
println(seq1 == seq2);

Ici, le résultat du script sera false parce que la deuxième séquence est plus longue que la première, les rendant de ce fait différentes.

Nous pouvons rendre les deux séquences différentes en modifiant les valeurs des éléments, même si les séquences ont toujours la même longueur :

 
Sélectionnez
var seq1 = [1, 2, 3, 4, 5];
var seq2 = [1, 3, 2, 4, 5];
println(seq1 == seq2);

À nouveau, ce code affichera false car les deux séquences sont différentes.

VI-H. L'utilisation de bouts de séquences

Les bouts de séquences fournissent un accès à des portions d'une séquence.

VI-H-1. seq[a..b]

Cette syntaxe donne accès aux éléments situés entre l'index a et l'index b, compris. Le script suivant crée une séquence weekend constituée uniquement des éléments « Sam » et « Dim ».

 
Sélectionnez
var jours = ["Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim"];
var weekend = jours[5..6];

VI-H-2. seq[a..<b]

Utiliser le caractère "<" pour accéder aux éléments situés entre l'index a compris et l'index b exclus. Nous utiliserons cela sur la séquence jours pour créer la séquence joursDeLaSemaine constitué des éléments « Lun » à « Ven ».

 
Sélectionnez
var jours = ["Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim"];
var joursDeLaSemaine = jours[0..<5];

VI-H-3. seq[a..]

En omettant le second index, vous pouvez accéder à tous les éléments de l'index a jusqu'à la fin de la séquence. En gardant le même exemple, nous pouvons créer la séquence weekend comme suit :

 
Sélectionnez
var jours = ["Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim"];
var weekend = jours[5..];

VI-H-4. seq[a..<]

Finalement, vous pouvez utiliser "<" sans le second index pour accéder à tout depuis l'index a jusqu'à la fin de la séquence, excluant le dernier élément.

 
Sélectionnez
var jours = ["Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim"];
var jours2 = jours[0..<];

Cette version créera une séquence jours2 constituée des éléments « Lun » jusque « Sam ».

VII. Les opérateurs

Les opérateurs sont des symboles spécifiques qui exécutent des opérations spécifiques sur un ou deux opérandes et retourne un résultat. Le langage de programmation JavaFX Script fournit des opérateurs d'assignation, des opérateurs arithmétiques, des opérateurs unitaires, des opérateurs d'égalité et de relation, des opérateurs conditionnels et un opérateur de comparaison de type.

VII-A. Opérateurs d'assignation

L'opérateur d'assignation "=" est l'un des opérateurs les plus couramment utilisés que vous pouvez rencontrer. Utilisez-le pour assigner la valeur située à droite de l'opérande à sa gauche.

 
Sélectionnez
resultat = nombre1 + nombre2;
jours = ["Lun", "Mar", "Mer", "Jeu", "Ven"];

Vous avez déjà utilisé cet opérateur dans les leçons précédentes.

VII-B. Les opérateurs arithmétiques

Les opérateurs arithmétiques permettent d'effectuer des addition, soustraction, multiplication et division. L'opérateur mod divise un opérande par un autre et retourne le reste comme résultat.

 
Sélectionnez
+ (opérateur d'addition)
- (opérateur de soustraction)
* (opérateur de multiplication)
/ (opérateur de division)
mod (opérateur de reste de division)

Le script suivant donne quelques exemples :

 
Sélectionnez
var resultat = 1 + 2; //resultat vaut maintenant 3
println(resultat);

resultat = resultat - 1; //resultat vaut maintenant 2
println(resultat);

resultat = resultat * 2; //resultat vaut maintenant 4
println(resultat);

resultat = resultat / 2; //resultat vaut maintenant 2
println(resultat);

resultat = resultat + 8; //resultat vaut maintenant 10
println(resultat);

resultat = resultat mod 7; //resultat vaut maintenant 3
println(resultat);

Vous pouvez également combiner les opérateurs arithmétiques avec l'opérateur d'assignation pour créer des assignations imbriquées. Par exemple, resultat += 1; et resultat = resultat + 1;. Tous les deux incrémentent la valeur de resultat de 1.

 
Sélectionnez
var resultat = 0;
resultat += 1;
println(resultat); // resultat vaut maintenant 1

resultat -= 1;
println(resultat); // resultat vaut maintenant 0

resultat = 2;
resultat *= 5; // resultat vaut maintenant 10
println(resultat);

resultat /= 2; // resultat vaut maintenant 5
println(resultat);

Le seul opérateur arithmétique qui ne peut être utilisé de cette façon est mod. Si, par exemple, vous désirez diviser le résultat par 2 et ensuite assigner le reste à lui-même, vous devrez écrire :

 
Sélectionnez
resultat = resultat mod 2;

VII-C. Les opérateurs unaires

La plupart des opérateurs requièrent deux opérandes. L'opérateur unaire utilise un seul opérande et permet des opérations comme incrémenter/décrémenter une valeur, rendre un nombre négatif, ou inverser la valeur d'un booléen.

 
Sélectionnez
- opérateur négation unaire; rends un nombre négatif
++ opérateur d'incrément; incrémente une valeur de 1
-- opérateur de décrément; décrémente une valeur de 1
not opérateur de complément logique; inverse la valeur d'un booléen

Le script suivant montre l'utilisation des opérateurs unaires :

 
Sélectionnez
var resultat = 1; // resultat vaut maintenant 1

resultat--;  // resultat vaut maintenant 0
println(resultat);

resultat++; // resultat vaut maintenant 1
println(resultat);

resultat = -resultat; // resultat vaut maintenant -1
println(resultat);

var succes = false;
println(succes); // false
println(not succes); // true

Les opérateurs d'incrément/décrément peuvent être appliqués avant (préfixe) ou après (suffixe) l'opérande. Les codes result++; et ++result; vont tous les deux finir avec result qui aura été incrémenté de 1. La seule différence est que la version avec le préfixe (++result;) évalue avec la valeur incrémentée alors que la version avec le suffixe (result++;) évalue avec la valeur d'origine (avant l'incrémentation).
Vous pouvez mémoriser lequel est lequel de cette façon : ++result fait l'incrément et donne la valeur result++ donne la valeur et ensuite fait l'incrément.
Si vous devez juste faire une incrémentation/décrémentation, il importe peu quelle version vous allez utiliser. Mais si vous utiliser ces opérateurs dans une expression, celle que vous choisirez aura une différence significative.

Le script qui suit illustre cette distinction :

 
Sélectionnez
var resultat = 3;
resultat++;
println(resultat); // resultat vaut maintenant 4
++resultat;
println(resultat); // resultat vaut maintenant 5
println(++resultat); // réeultat vaut maintenant 6
println(resultat++); // cela imprime toujours 6!
println(resultat); // mais resultat vaut maintenant 7

VII-D. Les opérateurs d'égalité et de relation

Les opérateurs d'égalité et de relation détermine si un opérande est plus grand que, plus petit que, égal à, ou différent d'un autre opérande.

 
Sélectionnez
==      égale à 
!=      différent de 
>       plus grand que 
>=      plus grand que ou égale à 
<       plus petit que
<=      plus petit que ou égale à 

Le script suivant teste ces opérateurs :

 
Sélectionnez
def nombre1 = 1;
def nombre2 = 2;

println(nombre1 == nombre2); // affiche false
println(nombre1 != nombre2); // affiche  true
println(nombre1 > nombre2);  // affiche  false
println(nombre1 >= nombre2); // affiche  false
println(nombre1 < nombre2);  // affiche  true
println(nombre1 <= nombre2); // affiche  true

VII-E. Les opérateurs conditionnels

Les opérateurs conditionnels ET et OU exécutent des opérations conditionnelles sur deux expressions booléennes.
Ces opérateurs ont un comportement de court-circuit ce qui signifie que le second opérande n'est évalué que si nécessaire. Par exemple, pour une opération and, si le résultat de la première expression est false, la seconde expression ne sera pas évaluée. Pour une opération or, si le résultat de la première expression est true, la seconde expression ne sera pas évaluée.

 
Sélectionnez
and
or

Le script suivant démontre l'utilisation de ces opérateurs en définissant les variables nomUtilisateur et motDePasse, puis en affichant le résultat de nombreuses conditions :

 
Sélectionnez
Test 1: nomUtilisateur ET motDePasse sont corrects
Test 3: nomUtilisateur OU motDePasse est correct
Test 4: nomUtilisateur OU motDePasse est correct

Le résultat est :

 
Sélectionnez
def nomUtilisateur = "foo";
def motDePasse = "bar";

if ((nomUtilisateur == "foo") and (motDePasse == "bar")) {
     println("Test 1: nomUtilisateur ET motDePasse sont corrects");
}

if ((nomUtilisateur == "") and (motDePasse == "bar")) {
     println("Test 2: nomUtilisateur ET motDePasse sont corrects");
}

if ((nomUtilisateur == "foo") or (motDePasse == "bar")) {
     println("Test 3: nomUtilisateur OU motDePasse est correct");
}

if ((nomUtilisateur == "") or (motDePasse == "bar")) {
     println("Test 4: nomUtilisateur OU motDePasse est correct");
}

VII-F. L'opérateur de comparaison de type

L'opérateur instanceof compare un objet à un type spécifié. Vous pouvez l'utiliser pour déterminer si un objet est une instance d'une classe particulière :

 
Sélectionnez
def string="Bonjour";
println(string instanceof String);  // affiche true

def nombre = 1031;
println(nombre instanceof java.lang.Integer); // affiche true

Vous trouverez cet opérateur très utile lorsque vous apprendrez plus à propos des classes et de l'héritage dans la dernière leçon de ce tutoriel.

VIII. Expressions

Les expressions sont des morceaux de code qui sont évalués et donnent une valeur en retour. Elles peuvent être combinées pour produire des expressions plus grandes. Le langage de programmation JavaFX Script est un langage d'expression, ce qui signifie que tout, y compris les boucles, les conditions et même les blocs, sont des expressions. Dans certains cas (comme les expressions while) les expressions ont une valeur de retour de type Void, ce qui signifie qu'elles ne retournent aucun résultat.

VIII-A. Les blocs

Un bloc est constitué d'une liste de déclarations ou d'expressions entourées d'accolades et séparées par des points-virgules. La valeur retournée par un bloc est la valeur de la dernière expression. Si le bloc ne contient pas d'expressions, le bloc est de type Void. Notez que var et def sont également des expressions.

L'expression de bloc suivant additionne quelques nombres et stocke le résultat dans une variable nommée total :

 
Sélectionnez
var nombres = [5, 7, 3, 9];
var total = {
     var somme = 0;
     for (a in nombres) { somme += a };
     somme;
}
println("Le total est de {total}.");

L'exécution de ce script produit le résultat suivant :

 
Sélectionnez
Le total est de 24.

La première ligne (var nombres = [5, 7, 3, 9];) déclare une séquence d'entiers.

La ligne suivante déclare une variable nommée total qui va contenir la somme de ces entiers.

L'expression de bloc qui suit est constituée de tout ce qui est entre accolades :

 
Sélectionnez
{
     var somme = 0;
     for (a in nombres) { somme += a };
     somme;
}

Dans ce bloc, la première ligne de code déclare une variable nommée somme qui contient la somme des entiers de cette séquence.
La seconde ligne (une expression for) boucle sur la séquence et ajoute chaque entier à la somme.
La dernière ligne indique la valeur de retour de l'expression de bloc (dans ce cas, 24).

VIII-B. L'expression if

L'expression if permet de diriger le déroulement d'un programme en exécutant certains blocs de code uniquement si une condition particulière est true.

Par exemple, le script suivant fournira le prix du ticket selon l'âge. Les personnes âgées de 12 à 65 ans payent le prix plein de 10 $. Les seniors et les enfants payeront 5 $, exceptés les enfants de moins de 5 ans qui ne payent rien.

 
Sélectionnez
def age = 8;
var prixDuTicket;

if (age < 5 ) {
     prixDuTicket = 0;
} else if (age < 12 or age > 65) {
     prixDuTicket = 5;
} else {
     prixDuTicket = 10;
}
println("Age: {age} Prix du Ticket : {prixDuTicket} dollars.");

Avec l'âge mis à 8, le script produit le résultat suivant :

 
Sélectionnez
Age: 8 Prix du Ticket : 5 dollars.

Si l'âge est moins de 5 ans, le prix du ticket est de 0 :

 
Sélectionnez
if (age < 5 ) {
     prixDuTicket = 0;
}

Si l'âge n'est pas plus petit que 5, le programme exécute la condition suivante (indiquée par le mot clé else suivi d'une autre expression if) :

 
Sélectionnez
else if (age < 12 or age > 65) {
     prixDuTicket = 5;
}

Cela met le prix du ticket à 5 $ si l'âge de la personne est entre 5 et 12 ou plus de 65 ans.

Si l'âge est entre 12 et 65 ans, le programme exécute le bloc de code final, indiqué par le mot clef else :

 
Sélectionnez
 else {
     prixDuTicket = 10;
}

Ce bloc ne s'exécute que si aucune des conditions précédentes ne sont satisfaites. Il met le prix du ticket à 10 $ pour les personnes âgées de 12 à 65 ans.

Le code précédent peut être écrit de façon très concise :

 
Sélectionnez
prixDuTicket = if (age < 5) 0 else if (age <12 or age > 65) 5 else 10;

C'est une technique très utile à maîtriser et que vous rencontrerez à nouveau dans ce tutoriel.

VIII-C. Les expression de séries

La leçon sur les séquences vous ont appris une notation abrégée pour déclarer une séquence de nombres qui forment une suite arithmétique :

 
Sélectionnez
var nombres : [0..5];

Techniquement parlant, [0..5] est une expression de série. Par défaut, l'intervalle entre les valeurs est de 1, mais vous pouvez utiliser le mot clef step pour spécifier un intervalle différent.

Par exemple, pour définir une séquence constituée de nombres impairs entre 1 et 10 :

 
Sélectionnez
var nombres = [1..10 step 2];
println(nombres);

Le résultat du script sera :

 
Sélectionnez
[1, 3, 5, 7, 9]

Pour créer une suite descendante, assurez-vous que la deuxième valeur soit plus petite que la première et spécifiez une valeur négative pour le pas :

 
Sélectionnez
var nombres = [10..1 step -1];
println(nombres);

Affichera :

 
Sélectionnez
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

Si vous ne fournissez pas de pas négatif lorsque vous créez une suite descendante, vous terminerez avec une séquence vide.

Le code suivant :

 
Sélectionnez
var nombres = [10..1 step 1];
println(nombres);

donnera un avertissement au moment de la compilation :

 
Sélectionnez
range.fx:1: warning: empty sequence range literal, probably not what you meant.
var nombres = [10..1 step 1];
           ^
1 warning

Vous obtiendrez également une séquence vide si vous omettez le mot clef step.

VIII-D. L'expression for

Après les expressions liées aux séquences, voici l'expression for. L'expression for fournit un mécanisme excellent pour boucler à travers les éléments d'une séquence.

Le code suivant fournit un exemple :

 
Sélectionnez
var jours = ["Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim"];
for (jour in jours) {
  println(jour);
}

Le résultat de ce script sera :

 
Sélectionnez
Lun
Mar
Mer
Jeu
Ven
Sam
Dim

Décortiquons quelque peu cet exemple.

Le mot-clef for, commence l'expression for :

 
Sélectionnez
for (jour in jours) {
  println(jour);
}

La variable jours est le nom de la séquence d'entrée qui sera traitée par l'expression for.

La variable jour contient la valeur courante pendant que l'expression for se déplace dans la séquence.

Notez que la variable jour ne doit pas être déplacée ailleurs dans le script avant d'être utilisée dans l'expression for.
De plus, jour ne sera pas accessible une fois l'expression for terminée. Les programmeurs donnent souvent à ces variables temporaires des noms courts (ou même d'une seule lettre).

Dans l'exemple précédent, rien ne montrait que for retourne une valeur. Cependant, for est également une expression qui retourne une séquence. Le code qui suit montre deux exemples de création d'une séquence depuis une autre, en utilisant l'expression for :

 
Sélectionnez
// La séquence qui en résulte contiendra le carré de chacun des nombres de la séquence d'entrée .
var carres = for (i in [1..10]) i*i; 

// La séquence qui en résult contient ["LUN", "MAR", "MER", etc]
var joursMajuscules = for (jour in jours) jour.toUpperCase(); 

La fonction toUpperCase() est fournie par l'objet String.
Vous pouvez obtenir la liste complète des fonctions en consultant la documentation de l'API.

VIII-E. L'expression while

Une autre façon d'écrire des boucles se fait à l'aide de l'expression while.
Contrairement à l'expression for, qui traite chaque élément d'une séquence, l'expression while va boucler jusqu'à ce qu'une condition donnée soit false.
Bien que while est syntaxiquement une expression, elle est de type Void et ne retourne dès lors pas de valeur.

Voici un exemple :

 
Sélectionnez
var compteur = 0;
while (compteur < 10) {
    println("compteur == {compteur}");
    compteur++;
} 

Le résultat de ce script sera :

 
Sélectionnez
compteur == 0
compteur == 1
compteur == 2
compteur == 3
compteur == 4
compteur == 5
compteur == 6
compteur == 7
compteur == 8 
compteur == 9

La première ligne déclare une variable nommée compteur et l'initialise à 0.

 
Sélectionnez
var compteur = 0;

La ligne qui suit commence l'expression while. Cette expression crée une boucle (entre les accolades ouvrante et fermante) qui se termine jusqu'à ce que la condition compteur < 10 soit évaluée à false.

 
Sélectionnez
while (count < 10) {
    ...
}

Le corps de l'expression while affiche la valeur courante de compteur, et incrémente ensuite sa valeur de 1.

 
Sélectionnez
println("compteur == {compteur}");
    compteur += 1;

Lorsque compteur vaut 10, il est mit fin à la boucle.
Pour créer une boucle infinie, placer le mot-clef true entre parenthèses, comme dans while(true) {}.

VIII-F. Les expression break et continue

De concert avec les expressions de boucle, on retrouve les expressions break et continue. Ces deux expressions vont affecter les itérations de boucle : break arrête entièrement la boucle, tandis que continue abandonne l'itération courante.

Bien que break et continue sont syntaxiquement des expressions, elles sont de type Void et ne retournent donc pas de valeur.

Exemple :

 
Sélectionnez
for (i in [0..10]) {
     if (i > 5) {
          break;
     }

     if (i mod 2 == 0) { //reste de la division par 2
          continue;
     }

     println(i);
}

Affiche :

 
Sélectionnez
1
3
5

Sans les expressions if, le programme afficherait tout simplement les nombres de 0 à 10.

Avec seulement la première expression if, le programme va sortir de la boucle lorsque la valeur de i sera supérieure à 5.

 
Sélectionnez
if (i > 5)  {
  break;
}

Dans ce cas, contine ne s'exécute que lorsque i est pair (c'est à dire lorsque le reste de la division de i par 2 vaut zéro). Lorsque cela se produit, la fonction println() n'est jamais invoquée et le nombre n'apparaît dès lors pas à la console.

VIII-G. Les expressions try, catch, throw et finally

Dans de réelles applications, il y aura toujours des moments où certains événements vont modifier le déroulement normal de l'exécution d'un script. Par exemple, si le script lit un fichier en entrée et que ce fichier n'est pas trouvé, le script ne sera pas capable de poursuivre son traitement. Nous appelons cette condition une « exception ».

Les exceptions sont des objets. Ces types sont généralement nommés d'après les conditions qu'ils représentent (par exemple, FileNotFoundException représente la condition d'un fichier qui ne peut être trouvé). Cependant, la définition d'un ensemble d'exceptions spécifiques aux exemples qui suivent va au-delà du sujet couvert dans cette section. Nous utiliserons donc un objet générique, Exception (emprunté du langage de programmation Java) pour démontrer les expressions throw, try, catch et finally.

Le script qui suit définit (et invoque) une fonction qui jette une exception :

 
Sélectionnez
import java.lang.Exception;

foo();

println("Le script s'est maintenant exécuté comme espéré... ");

function foo() {
     var quelquechoseafoire = false;

     if(quelquechoseafoire){
          throw new Exception("Quelque chose d'anormal s'est produit!");
     } else {
          println("La fonction s'est bien exécutée.");
     }
}

L'exécution de ce script tel quel (avec quelquechoseafoire valant false) affiche le message suivant :

 
Sélectionnez
La fonction s'est bien exécutée.
Le script s'est maintenant exécuté comme espéré...

Mais en mettant cette variable sur true, une exception sera jetée. À l'exécution, le script va échouer avec le message suivant :

 
Sélectionnez
Exception in thread "main" java.lang.Exception: Quelque chose d'anormal s'est produit!
at exceptions.foo(exceptions.fx:10)
at exceptions.javafx$run$(exceptions.fx:3)

Pour se prémunir de cet échec, il nous faut enrober l'invocation de la fonction foo() avec les expressions try/catch. Comme leur nom l'indique (du moins, pour un anglais), ces expressions essayent (try) d'exécuter le code entre accolades, mais va attraper (catch) une expression s'il y a un problème.

 
Sélectionnez
try {
     foo();
} catch (e: Exception) {
     println("{e.getMessage()} (mais nous l'avons attrapée)");
}

Maintenant, au lieu d'échouer, le programme affiche tout simplement :

 
Sélectionnez
Quelque chose d'anormal s'est produit! (mais nous l'avons attrapée)
Le script s'est maintenant exécuté comme espéré... 

Il existe également un bloc finally (ce n'est pas techniquement une expression) qui s'exécute toujours après que le bloc d'expression try soit exécuté, qu'il y ait eu une exception ou pas. Le bloc finally est utilisé pour exécuter des opérations de nettoyage qui doivent se dérouler que le bloc try se soit exécuté avec succès ou qu'une exception ait été générée.

 
Sélectionnez
try {
     foo();
} catch (e: Exception) {
     println("{e.getMessage()} (mais nous l'avons attrapée)");
} finally {
     println("Nous sommes maintenant dans l'expression finally...");
}

Ce qui donne maintenant à l'exécution :

 
Sélectionnez

Quelque chose d'anormal s'est produit! (mais nous l'avons attrapée)
Nous sommes maintenant dans l'expression finally...
Le script s'est maintenant exécuté comme espéré... 

IX. Data Binding et Triggers

Le Data Binding, ou la capacité de créer une relation directe et immédiate entre deux variables, est l'une des fonctionnalités les plus puissantes du langage de programmation JavaFX.
Cette leçon commence en liant deux simples variables et ira progressivement vers des liens plus sophistiqués : entre une variable et le résultat d'une fonction ou d'une expression. Une fois que vous aurez compris le concept, « Appliquer les Data Binding aux objets graphiques », une leçon du guide « Concevoir des Applications Graphiques avec JavaFX », donne un exemple de comment le Data Binding peut être un outil puissant pour concevoir des applications JavaFX.

Un trigger replace est un bloc de code qui est attaché à une variable (lorque la valeur de la variable change, le code est automatiquement exécuté).
Une application pratique d'un trigger replace est présentée.

IX-A. Binding Overview

Le mot-clef bind associe la valeur d'une variable cible avec la valeur d'une expression liée. L'expression liée peut être une simple valeur d'un type de base, d'un objet, le résultat d'une fonction ou le résultat d'une expression. Les sections qui suivent présenteront des exemples de chacun de ces cas.

IX-B. Binding et Objets

Dans la plupart des situations de programmation réelle, vous utiliserez les fonctionnalités de data binding pour garder l'interface utilisateur (GUI) d'une application en synchronisation avec les données sous-jacentes. La programmation d'un GUI est le sujet principal du guide « Concevoir des Applications Graphiques avec JavaFX » ; ici, nous allons expliquer les mécanismes sous-jacents de base, avec des exemples non-visuels.

Commençons simplement : le script qui suit lie la variable x à la variable y, change la valeur de x, et affiche celle de y. Parce que les variables sont liées, la valeur de y est automatiquement mise à jour avec la nouvelle valeur.

 
Sélectionnez
var x = 0;
def y = bind x;
x = 1;
println(y); // y vaut maintenant  1
x = 47;
println(y); // y vaut maintenant  47

Notez que nous avons déclaré la variable y comme def. Cela empêche n'importe quel code d'assigner directement une valeur à cette variable (bien que sa valeur peut changer selon le lien créé).

Vous devriez utiliser cette même convention lorsque vous liez à un objet (rappelez-vous que nous avons introduit Adresse dans « Utilisation d'objets ») :

 
Sélectionnez
var maRue: "1 Main Street";
var maVille: "Santa Clara":
var monEtat: "CA";
var monCodePostal:"95050";
var monPays:"USA";
def adresse = bind Adresse {
  rue: maRue;
  ville : maVille;
  etat : monEtat;
  codePostal : monCodePostal;
  adresse : monAdresse;
};

println("rue de l'adresse : {adresse.rue}");
maRue = "100 Mapple Street";
println("rue de l'adresse : {adresse.rue}");

En changeant la valeur de maRue, la variable rue dans l'objet adresse est affecté :

 
Sélectionnez
adresse.rue == 1 Main Street
adresse.rue == 100 Mapple Street

Notez que la modification de maRue provoque en fait la création d'un nouvel objet Adresse et le réassigne à la variable adresse. Pour traquer les modifications sans créer de nouvel objet Adresse, il vous faut associer directement les variables d'instance de l'objet :

 
Sélectionnez
def adresse = bind Adresse {
  rue: bind maRue;
  ville : bind maVille;
  etat : bind monEtat;
  codePostal : bind monCodePostal;
  adresse : bind monAdresse;
};

Vous pouvez également omettre le premier bind (celui juste avant Adresse) si vous avez explicitement liés les variables d'instance :

 
Sélectionnez
def adresse =  Adresse {
  rue: bind maRue;
  ville : bind maVille;
  etat : bind monEtat;
  codePostal : bind monCodePostal;
  adresse : bind monAdresse;
};

IX-C. Binding et les fonctions

Les leçons précédentes nous ont présenté les fonctions, mais il y a une autre distinction à faire : les fonctions liées et les fonctions non liées.

Considérez la fonction suivante, qui crée et retourne un objet Point :

 
Sélectionnez
var echelle = 1.0;

bound function creePoint(posX : Number, posY : Number) : Point {
     Point {
          x: posX * scale
          y: posY * scale
     }
}

class Point { 
     var x : Number;
     var y : Number;
}

C'est une fonction liée, parce qu'elle est précédée du mot-clef bound.

Le mot-clef bound ne remplace pas le mot-clef bind ; les deux sont utilisés conjointement comme décrit ci-dessous.

Ensuite, ajoutons du code pour invoquer cette fonction et tester nos binding :

 
Sélectionnez
var echelle = 1.0;

bound function creePoint(posX : Number, posY : Number) : Point {
     Point {
          x: posX * scale
          y: posY * scale
     }
}

class Point { 
     var x : Number;
     var y : Number;
}

var monX = 3.0;
var monY = 3.0;
def pt = bind creePoint(monX, monY);
println(pt.x);

monX = 10.0;
println(pt.x);

echelle = 2.0;
println(pt.x);

Le résultat de ce script est :

 
Sélectionnez
3.0
10.0
20.0

Analysons ce script partie par partie.

Le code :

 
Sélectionnez
var monX = 3.0;
var monY = 3.0;
def pt = bind creePoint(monX, monY);
println(pt.x);

initialise les variables de script monX et monY à 3.0.
Ces valeurs sont alors passées comme arguments à la fonction creePoint, qui crée et retourne un nouvel objet Point. Le mot-clef bind, placé juste avant l'invocation de creePoint, associe l'objet Point nouvellement créé (pt) au résultat de la fonction creePoint.

Ensuite, le code :

 
Sélectionnez
monX = 10.0;
println(pt.x);

change la valeur de monX à 10.0 et affiche la valeur de pt.x. La console montre que pt.x vaut maintenant 10.0.

Finalement, le code :

 
Sélectionnez
echelle = 2.0;
println(pt.x);

change la valeur de l'échelle et affiche à nouveau la valeur de pt.x. La valeur de pt.x est maintenant 20.0. Cependant, si nous enlevons le mot-clef bound de cette fonction (faisons d'elle une fonction non liée), le résultat sera :

 
Sélectionnez
3.0
10.0
10.0

C'est parce que les fonctions non-liées ne sont réinvoquées que lorsque l'un de leur argument change. Comme echelle n'est pas un argument de fonction, modifier ses valeurs ne provoque pas une nouvelle invocation de la fonction.

IX-D. Binding et les séquences

Vous pouvez également utiliser bind avec des expressions for. Pour explorer cela, définissons tout d'abord deux séquences et affichons les valeurs de leurs éléments :

 
Sélectionnez
var seq1 = [1..10];
def seq2 = bind for (item in seq1) item*2;
afficheSequences();

function afficheSequences() {
     println("Premiere Sequence :");
     for (i in seq1){println(i);}
     println("Seconde Sequence :");
     for (i in seq2){println(i);}
}

seq1 contient dix éléments (les nombres 1 à 10), seq2 contient également dix éléments ; ces éléments devraient avoir les même valeurs que seq1, mais nous avons appliqué l'expression item*2 à chacun, ce qui a pour effet de doubler leur valeur.

Le résultat est donc :

 
Sélectionnez
Premiere Sequence :
1
2
3
4
5
6
7
8
9
10
Seconde Sequence :
2
4
6
8
10
12
14
16
18
20

Nous pouvons lier les deux séquences en plaçant le mot-clef bind juste avant le mot clef for :

 
Sélectionnez
def seq2 = bind for (item in seq1) item*2;

La question vient maintenant : « Si seq1 change d'une façon ou d'une autre, est ce que tous les éléments (ou juste quelques uns) de seq2 seront affecté ? »
Nous pouvons tester cela en insérant un élément (la valeur 11) à la fin de seq1 et afficher les valeurs des deux séquences pour voir ce qui a changé :

 
Sélectionnez
var seq1 = [1..10];
def seq2 = bind for (item in seq1) item*2;
insert 11 into seq1;
afficheSequences();

function afficheSequences() {
     println("Premiere Sequence:");
     for (i in seq1){println(i);}
     println("Seconde Sequence:");
     for (i in seq2){println(i);}
}

Résultat :

 
Sélectionnez
Premiere Sequence :
1
2
3
4
5
6
7
8
9
10
11
Seconde Sequence :
2
4
6
8
10
12
14
16
18
20
22

Le résultat montre que l'insertion de 11 à la fin de seq1 n'affecte pas les 10 premiers éléments de seq2 : un nouvel élément est automatiquement rajouté à la fin de seq2 avec la valeur de 22.

IX-E. Les Triggers replace

Les Triggers replace sont des blocs de code arbitraires rattachés à des variables et sont exécutée lorsque la valeur de la variable change. L'exemple suivant montre la syntaxe de base : il définit une variable motDePasse et lui associe un trigger replace lorsque le mot de passe change, le trigger affiche un message indiquant la nouvelle valeur :

 
Sélectionnez
var motDePasse = "foo" on replace ancienneValeur {
     println("\nALERTE! Le mot de passe a ete modifie !");
     println("Ancienne valeur : {ancienneValeur}");
     println("Nouvelle valeur : {motDePasse}");
};

motDePasse = "bar";

Le résultat de cet exemple est :

 
Sélectionnez
ALERTE! Le mot de passe a ete modifie !
Ancienne valeur : 
Nouvelle valeur : foo

ALERTE! Le mot de passe a ete modifie !
Ancienne valeur : foo
Nouvelle valeur : bar

Le trigger dans cet exemple s'exécute deux fois ; premièrement lorsque motDePasse est initialisé à « foo » et ensuite lorsque la valeur devient « bar ». Notez que la variable ancienneValeur stocke la valeur de la variable avant que le trigger ne soit invoqué. Vous pouvez nommer cette variable comme vous le désirez. Nous l'avons appelée ancienneValeur car c'est un nom descriptif.

X. Écrire vos propres classes

Dans quasi toutes les applications JavaFX Script, vous désirerez écrire une ou plusieurs classes. Dans certains cas, vous écrirez une classe à partir de rien. Dans d'autres cas, vous désirerez étendre le comportement d'une classe existante. Cette leçon commence en montrant le script complet de la classe Client que vous avez déjà vue auparavant. Une classe abstraite, Compte est également présentée. Vous verrez alors comment étendre la classe pour créer les classes CompteEpargne et CompteCourant.

X-A. L'exemple Client

Dans la partie « Écriture de Scripts », vous avez appris comment utiliser des objets. Rappelez-vous cependant que nous vous avions demandé de télécharger un certain nombre de fichiers .class pour que le compilateur sache comment créer les objets Adresse et Client.
L'exemple suivant revisite ce code, rajoutant les définitions de classes manquantes pour que tout compile :

 
Sélectionnez
def client = Client {
     prenom: "John";
     nom: "Doe";
     telephone: "(408) 555-1212"
     adresse: Adresse {
          rue: "1 Main Street";
          ville: "Santa Clara";
          etat: "CA";
          codePostal: "95050";
          pays:"USA";
     }
}

client.afficheNom();
client.afficheTelephone();
client.afficheAdresse();

class Adresse {
     var rue: String;
     var ville: String;
     var etat: String;
     var codePostal: String;
     var pays: String;
}

class Client {
     var prenom: String;
     var nom: String;
     var telephone: String;
     var adresse: Address;

    function afficheNom() {
        println("Nom : {prenom} {nom}");
    }

    function afficheTelephone(){
        println("Telephone : {telephone}");
    }

    function afficheAdresse(){
        println("Rue : {adresse.rue}");
        println("Ville : {adresse.ville}");
        println("Etat : {adresse.etat}");
        println("Code Postal: {adresse.codePostal}");
        println("Pays: {adresse.pays}");
    }
}

Cet exemple devrait vous sembler familier puisque vous l'avez déjà rencontré lors des leçons sur les variables et les fonctions.
La classe Adresse déclare des instances de variables rue, ville, etat, codePostal et pays. Toutes de type String.
La classe Client déclare quelques instances de variables également, plus des fonctions qui affichent leurs valeurs. Parce que ces variables et fonctions sont déclarées dans des classes, elles sont disponibles pour n'importe quel objet Adresse et Client que vous créez.

X-B. Hériter d'autres classes

Vous pouvez également écrire des classes qui héritent des variables et fonctions d'autres classes. Par exemple, imaginer un compte d'épargne et un compte courant à la banque. Chacun a un numéro de compte et un solde. Vous pouvez obtenir le solde, faire des dépôts ou faire des retraits. Nous pouvons modéliser cela en créer une classe de base Compte qui fournit les variables et fonctions communes.

 
Sélectionnez
abstract class Compte {

     var numeroCompte: Integer;
     var solde: Number;

     function getSolde(): Number {
          return solde;
     }

     function depot(montant: Number): Void {
          solde += montant;
     }

     function retrait(montant: Number): Void {
          solde -= montant;
     }
}

Nous avons marqué cette classe comme étant abstraite (abstract), signifiant par là que les objets Compte ne peuvent être directement créés (le but de ce design est que vous ne pouvez créer que des comptes d'épargne ou des comptes courants).

Les variables numeroCompte et solde contiennent le numéro de compte et le solde actuel. Les fonctions fournissent le comportement de base pour obtenir le solde, faire un dépôt ou un retrait.

Nous pouvons définir une classe CompteEpargne qui va utiliser le mot-clef extends pour hériter de ces variables et fonctions :

 
Sélectionnez
class CompteEpargne extends Compte {

     var soldeMinimum = 100.00;
     var penalite = 5.00;

     function verifieSolde() : Void {
          if(solde < soldeMinimum){
               solde -= penalite;
          }
     }
}

Parce que CompteEpargne est une sous classe de Compte, elle va automatiquement contenir toutes les variables d'instance et fonction de Compte. Cela permet au code source de CompteEpargne de ne se concentrer que sur ce qui diffère de la classe parente (un requirement que le détenteur du compte d'épargne doit maintenir un solde minimum de 100 $ pour éviter des pénalités).

Nous pouvons définir, de façon similaire, la classe CompteCourant qui étend également la classe Compte :

 
Sélectionnez
class CompteCourant extends Compte {

     var nePeutEtreNegatif: Boolean;

     override function retrait(montant: Number) : Void {
          if(solde-montant<0 and nePeutEtreNegatif){

               // code pour interdire le retrait d'un compte protégé sera mis ici

          } else {
               solde -= montant; // le compte pourra avoir un solde négatif !
          }
     }
}

Cela diffère de Compte en définissant une variable qui vérifie si oui ou non le titulaire du compte est protégé contre les découverts (si un retrait, comme la signature d'un chèque, provoquerait un solde négatif, la protection contre le découvert s'active pour assurer que le chèque ne soit pas encaissé).
Notez que dans ce cas nous avons modifié le comportement de la fonction retrait héritée. C'est connu comme la surchage de fonction et indiqué par le mot clef override.

XI. Les Packages

Les Packages vous permettent d'organiser et de structurer vos classes et leurs relations envers les autres. Cette leçon vous guidera quant à la définition et l'utilisation d'un package.

Vous avez déjà maintenant une bonne connaissance des bases du langage de programmation JavaFX Script. Cependant, l'emplacement des fichiers source laisse quelque peu à désirer (pour le moment, vous avez probablement un seul répertoire rempli avec des tas d'exemples n'ayant aucun lien entre eux). Nous pouvons revoir toute notre organisation en plaçant notre code dans des packages.

Les packages permettent de grouper votre code par fonctionnalité. Cela donne également à vos classes un espace de nommage unique. Nous allons détailler tout cela pas par pas en mettant la classe Adresse dans un package spécifique.

XI-A. Étape 1 : choisir un nom de package

Avant que nous ne modifions du code, nous devons tout d'abord choisir un nom pour le package que nous allons créer. Puisque notre classe Adresse sera utilisée dans notre (non existante) application de carnet d'adresse, nous allons utiliser carnetadresse comme nom de package.

XI-B. Étape 2 : créer un répertoire

Ensuite, nous devons créer un répertoire carnetadresse quelque part sur notre disque dur. Ce répertoire va contenir les fichiers sources .fx pour n'importe quelle classe que nous désignerons comme appartenant au package carnetadresse.
Libre à vous de créer ce répertoire où bon vous semble. Nous utiliserons /home/demo/carnetadresse dans cet exemple, mais les scripts doivent être dans un répertoire ayant le même nom que le package. Dans notre cas, carnetadresse.

XI-C. Étape 3 : ajouter la déclaration de Package

Maintenant, allons dans le répertoire carnetadresse et créons le fichier source Adresse.fx. Copiez-y le code source suivant.
La première ligne fournit la déclaration de package, qui indique que cette classe appartient au package carnetadresse :

 
Sélectionnez
package carntadresse;

class Adresse {
     var rue: String;
     var ville: String;
     var etat: String;
     var codePostal: String;
     var pays: String;     
}

Notez que lorsqu'une déclaration de package est présente, elle doit apparaître comme première ligne de code dans le fichier source. Seule une déclaration de package par fichier source est permise.

XI-D. Étape 4 : ajouter les modificateurs d'accès

Ensuite, nous devons ajouter le mot-clé public à la classe Adresse et ses variables :

 
Sélectionnez
package carntadresse;

public class Adresse {
     public var rue: String;
     public var ville: String;
     public var etat: String;
     public var codePostal: String;
     public var pays: String;     
}

Ce mot clef est l'un des cinq modificateurs d'accès. Nous allons explorer les modificateurs d'accès dans la leçon suivante. Pour le moment, retenez juste que public rend ce code accessible aux autres classes et scripts.

XI-E. Étape 5 : compiler le code source

Tout en restant dans ce répertoire carnetadresse, compiler ce code source comme d'habitude avec la commande javafxc Adresse.fx (dans des projets logiciels plus larges, il y a des façons plus sophistiquées pour compiler du code réparti dans plusieurs packages, mais la compilation du code source dans ce répertoire suffira pour cet exemple). Après la compilation, ce répertoire va contenir les fichiers .class, résultats de la compilation.

XI-F. Étape 6 : utiliser la Classe

Nous sommes maintenant prêt à tester la classe Adresse modifiée. Mais tout d'abord, positionnons-nous dans le répertoire parent /home/demo. Ici, nous créerons un simple script test.fx qui testera l'utilisation du package carnetadresse.

Il y a plusieurs approches que nous pouvons prendre pour accéder à cette classe :

 
Sélectionnez
// Approche #1

carnetadresse.Adresse {
     rue: "1 Main Street";
     ville: "Santa Clara";
     etat: "CA";
     codePostal: "95050";
     pays: "USA";
}

L'approche 1 crée un objet en utilisant le nom de la classe pleinement qualifié (qui est maintenant carnetadresse.Adresse). Comparé à d'autres méthodes, cette approche vous semblera quelque peu rébarbative (surtout dans de larges scripts) mais vous devez savoir qu'elle existe.

 
Sélectionnez
// Approche #2
import carnetadresse.Adresse;

Adresse {
     rue: "1 Main Street";
     ville: "Santa Clara";
     etat: "CA";
     codePostal: "95050";
     pays: "USA";
}

L'approche #2 utilise le mot clef import qui permet l'utilisation du nom court (Adresse) partout dans le script. Cette approche est recommandée pour de larges programmes parce que ça aide à la documentation. D'un coup d'œil vous pouvez dire à quel package chaque classe appartient.

XII. Les modificateurs d'accès

Maintenant que vous avez compris le principe des packages, nous pouvons discuter des nombreux modificateurs d'accès fournis par le langage de programmation JavaFX Script. Ces mots clés spéciaux vous permettre de définir de nombreux niveaux de visibilité à vos variables, fonctions et classes.

XII-A. L'accès par défaut

L'accès par défaut, connu comme script-only est ce que vous obtenez lorsqu'aucun modificateur d'accès n'est précisé. C'est ce que nous avons utilisé principalement tout au long de ce tutoriel.

Quelques exemples :

 
Sélectionnez
var x;
var x : String;
var x = z + 22;
var x = bind f(q);

Avec ce niveau d'accès, les variables peuvent être initialisées, écrasées, lues, assignées ou liées dans le script uniquement. Aucun autre code source ne peut lire ou accéder à cette information.

XII-B. Le modificateur d'accès package

Pour rendre une variable, fonction, ou classe accessible à d'autres codes situés dans le même package, utilisez le modificateur d'accès package.

 
Sélectionnez
package var x;

Mais attention à ne pas confondre ce modificateur d'accès avec les déclarations de package, comme décrit dans la leçon précédente !

Exemple :

 
Sélectionnez
// Dans le fichier tutoriel/un.fx
package tutoriel; // place ce script dans le package "tutoriel"
package var message = "Bonjour de un.fx !"; // c'est le modificateur d'accès "package"
package function afficheMessage() {
     println("{message} (dans la fonction afficheMessage)");
}

// Dans le fichier tutoriel/deux.fx
package tutoriel;
println(un.message);
un.printMessage();

Vous pouvez compiler et exécuter cet exemple (depuis le répertoire parent de tutoriel) avec les commandes suivantes :

 
Sélectionnez
javafxc tutoriel/un.fx tutoriel/deux.fx
javafx tutoriel/deux

Le résultat sera :

 
Sélectionnez
Bonjour de un.fx !
Bonjour de un.fx ! (dans la fonction afficheMessage)

XII-C. Le modificateur d'accès protected

Le modificateur d'accès protected rend la variable ou fonction accessible à d'autres codes du même package, ainsi qu'à des sous-classes situées dans n'importe quel package.

Exemple :

 
Sélectionnez
// Dans le fichier tutoriel/un.fx
package tutoriel;
public class un {
     protected var message = "Bonjour !";
}

// Dans le fichier deux.fx
import tutoriel.un;
class deux extends un {
     function afficheMessage() {
          println("Classe deux dit {message}");
     }
};

var t = deux{};
t.afficheMessage();

Compiler et exécuter cette démo :

 
Sélectionnez
javafxc tutoriel/un.fx deux.fx
javafx deux

Ce qui donne :

 
Sélectionnez
Classe deux dit Bonjour !

Notez que ce modificateur d'accès ne peut s'appliquer aux classes. C'est pourquoi nous avons marqué la classe un comme public

XII-D. Le modificateur d'accès public

Une classe, variable, ou fonction public a le plus de visibilité. Elle peut être accessible depuis n'importe quelle classe, ou script, quel que soit le package.

Exemple :

 
Sélectionnez
// Dans le fichier tutoriel/un.fx
package tutoriel;
public def unMessage = "C'est une variable de script public dans un.fx";
public class un {
     public var message = "bonjour de la classe un !";
     public function afficheMessage() {
          println("{message} (dans la fonction afficheMessage)");
     }
}

// Dans le fichier deux.fx
import tutoriel.un;
println(un.unMessage);
var o = un{};
println(o.message);
o.afficheMessage();

Compiler et exécuter cet exemple :

 
Sélectionnez
javafxc tutoriel/un.fx deux.fx
javafx deux

Résultat :

 
Sélectionnez
C'est une variable de script public dans un.fx
bonjour de la classe un !
bonjour de la classe un ! (dans la fonction afficheMessage)

XII-E. Le modificateur d'accès public-read

Le modificateur d'accès public-read définit un variable qui est publiquement accessible en lecture, mais (par défaut) n'est accessible en écriture que dans le script courant. Pour étendre ses accès en écriture, il vous faudra le faire précéder les modificateurs d'accès package ou protected (c.à.d. package public-read ou protected public-read). En faisant cela, les accès en écriture seront également possibles au niveau du package ou au niveau protected.

Exemple :

 
Sélectionnez
// Dans le fichier tutoriel/un.fx
package tutoriel;
public-read var x = 1;

// Dans tutoriel/deux.fx
package tutoriel;
println(un.x);

Compiler et exécuter cet exemple :

 
Sélectionnez
javafxc tutoriel/un.fx tutoriel/deux.fx
javafx tutoriel/deux

Le résultat est "1" ce qui prouve que x est bien accessible en lecture en dehors du script tutoriel/un.

Maintenant, essayons de modifier sa valeur :

 
Sélectionnez
// Dans tutoriel/deux.fx
package tutoriel;
un.x = 2;
println(un.x);

Cela donnera une erreur au moment de la compilation :

 
Sélectionnez
tutoriel/deux.fx:3: x has script only (default) write access in tutoriel.un
un.x = 2;
   ^
1 error

Pour que cela fonctionne, nous devons étendre les accès en écriture à x :

 
Sélectionnez
// Dans le fichier tutoriel/un.fx
package tutoriel;
package public-read var x = 1;

// Dans tutoriel/deux.fx
package tutoriel;
un.x = 2;
println(un.x);

Cet exemple va maintenant compiler et afficher "2" à l'écran.

XII-F. Le modificateur d'accès public-init

Le modificateur d'accès public-init définit une variable qui peut être publiquement initialisée par des littéraux d'objets dans n'importe quel package.
Les accès en écriture qui pourraient suivre, cependant, sont contrôlés de la même manière que public-read (le défaut est accès en écriture au niveau du script, mais en le faisant précéder de package ou protected, on va étendre l'accès au niveau correspondant). La valeur de cette variable est toujours accessible en lecture depuis n'importe quel package.

Exemple :

 
Sélectionnez
// Dans le fichier tutoriel/un.fx
package tutoriel;
public class un {
     public-init var message;
}

// Dans le fichier deux.fx
import tutoriel.un;
var o = un {
     message: "variable initialisee depuis un autre package !"
}
println(o.message);

Compiler et exécuter l'exemple :

 
Sélectionnez
javafxc tutoriel/un.fx deux.fx
javafx deux

Cela affiche variable initialisee depuis un autre package ! prouvant qu'un objet situé dans un autre package peut initialiser la variable message. Cependant, du fait que les accès en écriture qui pourraient suivre ne sont possibles que dans le script, nous ne pouvons en changer sa valeur :

 
Sélectionnez
// Dans le fichier deux.fx
import tutoriel.un;
var o = un {
     message: "variable initialisee depuis un autre package !"
}
o.message = "Changement du message ..."; //ERREUR DE COMPILATION
println(o.message);

L'erreur à la compilation est celle-ci :

 
Sélectionnez
deux.fx:12: message has script only (default) write access in tutoriel.un
o.message = "Changement du message ..."; //ERREUR DE COMPILATION
 ^
1 error

Cela confirme le comportement espéré : la variable peut être publiquement initialisée, mais les tentatives d'écriture qui suivraient sont contrôlées par un niveau d'accès différent.