Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

Vous n'avez pas encore de compte Developpez.com ? L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Developpez.com

Qt

Choisissez la catégorie, puis la rubrique :

Viadeo Twitter Facebook Share on Google+   
Logo Documentation Qt ·  Page d'accueil  ·  Toutes les classes  ·  Toutes les fonctions  ·  Vues d'ensemble  · 

Intégration de JavaScript

QML encourage la construction déclarative des interfaces utilisateur, en utilisant la liaison de propriétés et la composition d'éléments QML existants. Afin de permettre l'implémentation de comportements plus avancés, QML s'intègre étroitement avec du code JavaScript impératif.

L'environnement JavaScript fourni par QML est plus strict que celui d'un navigateur web. En QML vous ne pouvez pas ajouter ou modifier des membres de l'objet global JavaScript. En JavaScript, il est possible de modifier accidentellement l'objet global en utilisant une variable sans la déclarer ; en QML, cela lève une exception, toutes les variables locales doivent donc être déclarées explicitement.

En plus des propriétés standard JavaScript, l'objet QML global inclut des méthodes d'aide qui simplifient la construction des interfaces utilisateur et l'interaction avec l'environnement QML.

JavaScript en ligne

Les petites fonctions JavaScript peuvent être écrites en ligne (inline) avec d'autres déclarations QML. Ces fonctions en ligne sont ajoutées comme méthodes à l'élément QML qui les contient.

 Item {
     function factorielle(a) {
         a = parseInt(a);
         if (a <= 0)
             return 1;
         else
             return a * factorielle(a - 1);
     }
 
     MouseArea {
         anchors.fill: parent
         onClicked: console.log(factorielle(10))
     }
 }

En tant que méthodes, les fonctions en ligne dans l'élément racine d'un composant QML peuvent être invoquées par des appelants en dehors du composant. Si cela est indésirable, la méthode peut être ajoutée à un élément qui ne fait pas partie de la racine ou, de préférence, écrite dans un fichier JavaScript externe.

Fichiers JavaScript séparés

Les gros blocs de JavaScript doivent être écrits dans des fichiers séparés. Ces fichiers peuvent être importés dans des fichiers QML en utilisant la déclaration import, de la même manière que les modules sont importés.

Par exemple, la méthode factorielle() dans l'exemple ci-dessus pour le JavaScript en ligne peut être déplacée vers un fichier externe nommé factorielle.js et on peut y accéder comme suit :

 import "factorielle.js" as MathFunctions
 Item {
     MouseArea {
         anchors.fill: parent
         onClicked: console.log(MathFunctions.factorielle(10))
     }
 }

Les URL JavaScript relatives et absolues peuvent toutes les deux être importées. Dans le cas d'une URL relative, l'emplacement est résolu relativement à l'emplacement du document QML qui contient l'importation. Si le fichier du script n'est pas accessible, une erreur va survenir. Si le JavaScript a besoin d'être récupéré depuis une ressource réseau, le status du composant est mis à « Loading » jusqu'à ce que le script ait été téléchargé.

Les fichiers JavaScript importés sont toujours qualifiés en utilisant le mot-clé as. Le qualificateur pour les fichiers JavaScript doit être unique, pour qu'il y ait toujours une correspondance un-pour-un entre les qualificateurs et les fichiers JavaScript (cela signifie aussi que les qualificateurs ne peuvent pas porter les mêmes noms que les objets JavaScript intégrés tel que Date et Math).

Fichiers séparés d'implémentation du code

La plupart des fichiers JavaScript importés dans un fichier QML sont des implémentations logiques, à état, pour le fichier QML qui les importe. Dans ces cas et pour que les instances de composants QML se comportent correctement, chaque instance requiert une copie séparée des objets et états JavaScript.

Le comportement par défaut lors de l'importation des fichiers JavaScript est de fournir une copie unique et isolée pour chaque instance de composant QML. Le code s'exécute dans le même cadre que l'instance de composant QML et peut par conséquent accéder aux objets et propriétés déclarées et les manipuler.

Bibliothèques JavaScript sans état

Certains fichiers JavaScript se comportent davantage comme des bibliothèques, ils fournissent un ensemble de fonctions d'aide sans état qui prennent l'entrée et calculent la sortie mais ne manipulent jamais les instances de composants QML directement.

Pour éviter de gaspiller des ressources en donnant à chaque instance de composant QML une copie unique de ces bibliothèques, le programmeur JavaScript peut indiquer qu'un fichier particulier est une bibliothèque sans état à travers l'utilisation d'une directive pragma, comme montré dans l'exemple suivant.

 // factorielle.js
 .pragma library
 
 function factorielle(a) {
     a = parseInt(a);
     if (a <= 0)
         return 1;
     else
         return a * factorielle(a - 1);
 }

La déclaration de la directive pragma doit apparaître avant tout code JavaScript, excluant les commentaires.

Comme ils sont partagés, les fichiers de bibliothèque sans état ne peuvent pas accéder directement aux objets instances de composants QML, bien que les valeurs QML peuvent être passées en tant que paramètres de fonction.

Importation d'un fichier JavaScript depuis un autre

Si un fichier JavaScript a besoin d'utiliser des fonctions définies à l'intérieur d'un autre fichier JavaScript, cet autre fichier peut être importé en utilisant la fonction Qt.include(). Ceci importe toutes les fonctions depuis l'autre fichier vers l'espace de noms du fichier courant.

Par exemple, le code QML ci-dessous à gauche appelle montrerLesCalculs() dans script.js, qui à son tour peut appeler factorielle() dans factorielle.js, parce qu'il a inclus factorielle.js en utilisant Qt.include().

 import QtQuick 1.0
 import "script.js" as MonScript
 
 Item {
     width: 100; height: 100
 
     MouseArea {
         anchors.fill: parent
         onClicked: {
             MyScript.montrerLesCalculs(10)
             console.log("Appel de factorielle() depuis QML:",
                 MonScript.factorielle(10))
         }
     }
 }
 // script.js
 Qt.include("factorielle.js")
 
 function montrerLesCalculs(valeur) {
     console.log("Appel de factorielle() depuis script.js:",
         factorielle(valeur));
 }
 // factorielle.js
 function factorielle(a) {
     a = parseInt(a);
     if (a <= 0)
         return 1;
     else
         return a * factorielle(a - 1);
 }

Notez que l'appel de Qt.include() importe toutes les fonctions depuis factorielle.js dans l'espace de noms MonScript, ce qui veut dire que le composant QML peut aussi accéder à factorielle() directement en tant que MonScript.factorielle().

Exécution de JavaScript au démarrage

Il est parfois nécessaire d'exécuter du code impératif au démarrage de l'application (ou d'une instance de composant). Bien qu'il soit tentant de juste inclure le script de démarrage comme code global dans un fichier de script externe, ceci peut impliquer des limitations sévères puisque l'environnement QML peut ne pas avoir été complètement établi. Par exemple, certains objets peuvent ne pas avoir été créés ou certaines liaisons de Propriété peuvent ne pas avoir été exécutées. Restrictions JavaScript QML couvre les limitations exactes du code script global.

L'élément Composant QML fournit une propriété attachée onCompleted qui peut être utilisée pour déclencher l'exécution du code script au démarrage après que l'environnement QML ait été complètement établi. Par exemple:

 Rectangle {
     function fonctionDeDémarrage() {
         // ... code de démarrage
     }
 
     Component.onCompleted: fonctionDeDémarrage();
 }

Tout élément dans un fichier QML - y compris les éléments imbriqués et les instances de composants QML imbriqués - peut utiliser cette propriété attachée. S'il y a plus qu'un gestionnaire onCompleted() à exécuter au démarrage, ils sont exécutés séquentiellement dans un ordre indéfini.

De même, la propriété attachée Component::onDestruction est amorcée à la destruction du composant.

Comparaison entre affectation de propriété et liaison de propriété

Quand on travaille avec QML et JavaScript, il est important de faire la distinction entre liaison de Propriété et affectation de valeur JavaScript. En QML, une liaison de propriété est créée en utilisant la syntaxe propriété: valeur :

 Rectangle {
     largeur: autreItem.largeur
 }

La largeur du Rectangle ci-dessus est mise à jour chaque fois que autreItem.largeur change. D'autre part, prenez l'extrait de code JavaScript suivant, qui s'exécute quand le Rectangle est créé :

 Rectangle {
 
     Component.onCompleted: {
         largeur = autreItem.largeur;
     }
 }

La valeur de autreItem.largeur est affectée à la largeur de ce Rectangle en utilisant la syntaxe propriété = valeur dans JavaScript. À la différence de la syntaxe propriété: valeur, ceci n'invoque pas la liaison de propriété QML ; la valeur de autreItem.largeur devient égale à la propriété rectangle.largeur au moment de l'affectation et ne va pas être mise à jour si cette valeur change.

Voir liaison de propriété pour plus d'informations.

Réception des signaux QML dans JavaScript

Pour recevoir un signal QML, utilisez la méthode du signal connect() pour le connecter à une fonction JavaScript.

Par exemple, le code suivant connecte le signal clicked de MouseArea à functionJS() dans script.js :

 import QtQuick 1.0
 import "script.js" as MonScript
 
 Item {
     id: item
     width: 200; height: 200
 
     MouseArea {
         id: mouseArea
         anchors.fill: parent
     }
 
     Component.onCompleted: {
         mouseArea.clicked.connect(MonScript.functionJS)
     }
 }
 // script.js
 
 function functionJS() {
     console.log("Fonction JavaScript appelée!")
 }

La fonctionJS() va maintenant être appelée à chaque fois que le signal clicked de MouseArea est émis.

Voir écrire des composants QML : propriétés, méthodes et signaux pour plus d'informations.

Restrictions du JavaScript de QML

QML exécute du code JavaScript standard, avec les restrictions suivantes :

  • le code JavaScript ne peut pas modifier l'objet global.

En QML, l'objet global est constant - les propriétés existantes ne peuvent pas être modifiées ou supprimées et on ne peut pas créer de nouvelles propriétés.

La plupart des programmes JavaScript ne modifient pas intentionnellement l'objet global. Cependant, la création automatique par JavaScript des variables non déclarées est une modification implicite de l'objet global, et est interdite dans QML.

En supposant que la variable a n'existe pas dans la portée, le code suivant est illégal en QML.

 // Modification illégale d'une variable non déclarée
 a = 1;
 for (var ii = 1; ii < 10; ++ii)
     a = a * ii;
 console.log("Résultat: " + a);

Ce code peut être trivialement modifié pour devenir légal.

 var a = 1;
 for (var ii = 1; ii < 10; ++ii)
     a = a * ii;
 console.log("Résultat: " + a);

Toute tentative de modifier l'objet global - que ce soit implicitement ou explicitement - va causer une exception. Si elle n'est pas interceptée, elle va causer l'impression d'un avertissement incluant le fichier et le numéro de ligne du code incriminé.

  • Le code Global est exécuté dans une portée réduite.

Pendant le démarrage, si le fichier QML inclut un fichier JavaScript externe avec du code « global », il est exécuté dans une portée qui contient seulement le fichier externe lui-même et l'objet global. Ce qui veut dire qu'il n'aura pas accès aux objets et propriétés QML auxquels il a normalement accès.

Un code global accédant seulement aux variables locales du script est autorisé. Ceci est un exemple de code global valide.

 var couleurs = [ "rouge", "bleu", "vert", "orange", "violet" ];

Un code global qui accède aux objets QML ne va pas s'exécuter correctement.

 // Code global invalide - la variable "objectRacine" est indéfinie
 var positionInitiale = { objectRacine.x, objectRacine.y }

Cette restriction existe car l'environnement QML n'est pas encore complètement établi. Pour exécuter le code après la fin de l'initialisation de l'environnement, référez-vous à Éxécution de JavaScript au Démarrage.

  • La valeur de this est actuellement indéfinie en QML.

La valeur de this est indéfinie en QML. Pour se référer aux éléments, fournissez un id. Par exemple :

 Item {
     width: 200; height: 100
     function regionSourisCliquee(région) {
         console.log("Cliqué dans la région à: " + region.x + ", " + region.y);
     }
     // Ceci ne va pas marcher car "this" est indéfini
     RegionSouris {
         height: 50; width: 200
         onClicked: regionSourisCliquee(this)
     }
     // Ceci va passer région2 à la fonction
     RegionSouris {
         id: region2
         y: 50; height: 50; width: 200
         onClicked: regionSourisCliquee(region2)
     }
 }

Remerciements

Merci à Houssem Lamti pour la traduction ainsi qu'à Ilya Diallo, Jonathan Courtois, Thibaut Cuvelier et Claude Leloup pour leur relecture !

Cette page est une traduction d'une page de la documentation de Qt, écrite par Nokia Corporation and/or its subsidiary(-ies). Les éventuels problèmes résultant d'une mauvaise traduction ne sont pas imputables à Nokia. Qt 4.7
Copyright © 2020 Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon, vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts. Cette page est déposée à la SACD.
Vous avez déniché une erreur, une redirection cassée ou tout autre problème, quel qu'il soit ? Ou bien vous désirez participer à ce projet de traduction ? N'hésitez pas à nous contacter ou par MP !
Responsable bénévole de la rubrique Qt : Thibaut Cuvelier -

Partenaire : Hébergement Web