
FAQ JavaFXConsultez toutes les FAQ
Nombre d'auteurs : 4, nombre de questions : 86, dernière mise à jour : 18 mai 2009
Sommaire→Langage→Les Fonctions→Fonctions AvancéesPour JavaFX, une signature de fonction est un type comme un autre. Il est donc possible de définir une variable comme étant une référence sur une fonction et appeler ainsi cette fonction quand on appelle cette variable.
Pour ce faire, il faut déclarer la variable suivie de deux points (:) , puis du mot-clé function puis de la liste des arguments de la fonction entre parenthèse puis de deux-points (:) et de son type de retour.
var bonjour: function():Void;
Ici, bonjour est une référence vers une fonction qui ne
prend pas d'argument et ne retourne rien.
Par défaut, bonjour est initialisé à null. Si nous appellons :
bonjour() ;
Rien ne se passe.
De plus si nous imprimons la valeur de bonjour en faisant :
println(bonjour) ;
Nous obtenons :
null
Nous pouvons cependant lui affecter une valeur.
Définissons par exemple la fonction suivante :
function direBonjour() {
println("Salut le monde !");
}
Si nous faisons :
var bonjour: function():Void;
function direBonjour() {
println("Salut le monde !");
}
bonjour = direBonjour;
bonjour();
Notre programme va afficher le message Salut le monde !.
Si nous imprimons la valeur de bonjour, nous obtiendrons
quelques chose de similaire à :
monScript$1@1506dc4
qui est la valeur de la référence sur la fonction que nous utilisons.
Nous pouvons bien sur affecter d'autres valeurs à notre variable en cours d'exécution, ainsi le code suivant :
println(bonjour);
bonjour();
println("=============================");
function test1():Void {
println("Hello world!");
}
bonjour = test1;
println(bonjour);
bonjour();
println("=============================");
function test2():Void {
println("Salut le monde !");
}
bonjour = test2;
println(bonjour);
bonjour();
Produira quelques chose de similaire à :
=============================
null
=============================
monScript$1@1506dc4
Hello world!
=============================
monScript$2@a761fe
Salut le monde !
Car
- La variable est initialisée à null rien ne s'affiche.
- La variable prend la référence de la fonction test1() et affiche Hello world!.
- La variable prend la référence de la fonction test2() et affiche Salut le monde !.
Si nous essayons d'affecter des fonctions dont la signature ne correspond
pas à la définition de notre variable, des erreurs seront générées par le
compilateur ou l'IDE.
Ainsi le code suivant ne compilera pas :
function test3(x:Number):Void {
println("{x}");
}
bonjour = test3;
println(bonjour);
bonjour ();
function test4():Number {
return 0;
}
bonjour = test4;
println(bonjour);
bonjour ();
En effet, aucune des deux fonctions ne correspond à la signature utilisée pour la définition de bonjour.
Il est bien sûr possible de définir des signatures de référence sur des fonctions prenant en paramètres plusieurs arguments ou ayant des types de retour. Ainsi le code suivant est tout à fait valide :
var add:function(x:Number, y:Number):Number;
function addNumber(x:Number, y:Number):Number {
return x+y;
}
add=addNumber;
println(add(3, 4));
Une fois executé ce code affichera la valeur 7.0.
On remarquera également qu'il est impossible d'appeler la variable add sans argument ou avec le mauvais nombre d'arguments entre les parenthèses car cela ne correspond pas à la signature utilisée. Ainsi, le code suivant ne compilera pas :
println(add());
println(add(1));
println(add(1, 2, 3));
Avant d'utiliser des références de fonction, vous devez cependant
prendre garde à ce que vos références soient correctement
initialisées.
Ainsi :
var add:function(x:Number, y:Number):Number;
println(add(3, 4));
println(add);
println("=============================");
function addNumber(x:Number, y:Number):Number {
return x+y;
}
add=addNumber;
println(add(3, 4));
println(add);
Produira un résultat similaire à :
0.0
null
=============================
7.0
monScript$1@a761fe
En effet,
- La variable add est non-initialisée et donc à null. La valeur retournée est 0.0 qui est la valeur par défaut pour Number.
- La variable add est initialisée avec notre fonction et retourne la valeur correcte.
Il faudra donc manier ce concept avec précautions.
Il est possible de faire un callback en créant une variable qui est une
référence de fonction à l'intérieur d'une classe.
Par exemple :
public class Toto {
public var onXXXChange:function():Void;
public function faireQuelqueChose():Void {
onXXXChange();
}
}
Dans ce cas, la variable onXXXChange est définie comme étant une
référence sur une fonction qui ne prend pas d'argument et qui ne
retourne rien.
Nous pouvons donc appeler cette variable comme s'il s'agissait d'une
fonction depuis le code de la classe et il est également possible
d'accéder directement à cette variable depuis l'extérieur de la classe.
Par défaut la variable est initialisée à null et le code ne fait
strictement rien.
Note : le nom de la variable importe peu et vous pouvez la nommer comme bon vous semble.
Si nous écrivons
var toto1 = Toto{
}
toto1.faireQuelqueChose();
A l'exécution, il ne se passe rien.
Lorsque nous implémentons notre classe, il est possible de redéfinir la variable onXXXChange comme n'importe quelle autre variable publique qui ne soit pas marquée public-read.
Par exemple :
var toto2 = Toto {
onXXXChange: function():Void {
println("onXXXChange");
}
}
toto2.faireQuelqueChose();
À l'execution, le texte onXXXChange s'affichera.
Vous pouvez remarquer que la gestion des évènements claviers et souris
dans l'API SceneGraph fonctionne exactement de la même manière.
Vous serez donc ammener à surcharger les valeurs par défaut des variables
onMouseClicked ou onKeyPressed (par exemple) pour gérer les
événements dans la classe javafx.stage.Node et ses classes filles.
Vous pouvez sans problème définir des variables avec des signatures
de fonction qui prennent plusieurs arguments ou qui ont même un type de
retour.
Dans tous les cas, vous devrez faire attention à ce que vos variables
soient correctement définies :
public class Toto {
public var onXXXChange:function():Void;
public var onYYYChange:function(x:Number, y:Number):Number;
public function faireQuelqueChose1():Void {
onXXXChange();
}
public function faireQuelqueChose2(x:Number, y:Number):Number {
return onYYYChange(x, y);
}
}
var toto1 = Toto{
}
var toto2 = Toto {
onXXXChange: function():Void {
println("onXXXChange");
}
onYYYChange: function(x:Number, y:Number):Number {
println("{x}, {y}");
return x+y;
}
}
println("=======================");
toto1.faireQuelqueChose1();
println(toto1.onYYYChange);
println(toto1.onYYYChange(1, 2));
println(toto1.faireQuelqueChose2(1, 2));
println("=======================");
toto2.faireQuelqueChose1();
println(toto2.onYYYChange);
println(toto2.onYYYChange(1, 2));
println(toto2.faireQuelqueChose2(1, 2));
Le résultat de l'exécution d'un tel code sera :
=======================
null
0.0
0.0
=======================
onXXXChange
monScript$2@1be0f0a
1.0, 2.0
3.0
1.0, 2.0
3.0
- L'appel à la methode faireQuelqueChose1() n'imprime rien car onXXXChange n'est pas défini.
- L'impression directe de onYYYChange affiche null car onYYYChange n'est pas défini.
- L'acces direct direct à onYYYChange retourne retourne 0.0 qui est la valeur des Number (le type de retour dans la signature de la fonction) par défaut.
- L'appel à la méthode faireQuelqueChose2() retourne 0.0 qui est la valeur des Number par défaut.
- L'appel à la méthode faireQuelqueChose1() imprime bien onXXXChange puisque la fonction que nous avons définie est appelée.
- L'impression directe de onYYYChange affiche la référence de la fonction que nous avons defini.
- L'accès direct à onYYYChange imprime bien les valeurs de x et y et retourne le résultat correct de la fonction que nous avons défini.
- L'appel à la méthode faireQuelqueChose2() imprime bien les valeurs de x et y et retourne le résultat correct de la fonction que nous avons défini.
Une fois de plus, il faudra donc manier ce concept avec précautions.


















