Différences entre versions de « Tutoriel:Éviter des tâches répétitives en éditant le code XML »

De GeoGebra Manual
Aller à : navigation, rechercher
Ligne 93 : Ligne 93 :
 
Ces scripts modifient l'entier n, qui, via le dynamisme des constructions de geogebra, actualise la position des points A0 ... A4.  
 
Ces scripts modifient l'entier n, qui, via le dynamisme des constructions de geogebra, actualise la position des points A0 ... A4.  
 
* Pour le point A0, l'interaction est simple, si la boule est activée (y(A0)=6), retirer 500000, sinon ajouter 500000.  
 
* Pour le point A0, l'interaction est simple, si la boule est activée (y(A0)=6), retirer 500000, sinon ajouter 500000.  
* Pour le points suivants, par exemple A2: on vérifie qu'on peut le bouger vers le haut (y(A2)=2 et y(A1)=4)), si oui on augmente n de 100000, sinon on vérifie qu'on peut le bouger vers le bas ( y(A2)=3 et y(A3)=1), si oui on diminue n de 100000, sinon on laisse n inchangé (boule non déplaçable). Il y a un test de moins pour A1 et A4.
+
* Pour le points suivants, par exemple A2: on vérifie qu'on peut le bouger vers le haut (y(A2)=2 et y(A1)=4)), si oui on augmente n de 100000, sinon on vérifie qu'on peut le bouger vers le bas ( y(A2)=3 et y(A3)=1), si oui on diminue n de 100000, sinon on laisse n inchangé (boule non déplaçable). Il y a un test de moins pour A1 et A4, qui sont des boules qui n'ont qu'un voisin.
 +
 
 +
== Dupliquer à l'aide du code XML ==
 +
On peut alors ... refaire la même chose pour toutes les tiges  (ouf! autant de scripts que de points...) ou essayer de tirer parti de la logique de notation pour appliquer en masse du copier/coller. Une commande 'SoitScript' permettrait d'entrer ces scripts via une commande Exécute et quelques aspirines, mais en l'absence de cette commande, on peut attaquer le code XML. La procédure est la suivante (les commandes sont celles de Linux, mais il suffit d'adapter):
 +
* Faire une copie du fichier geogebra en fichier zip: <code>cp boulier.ggb boulier.zip</code> et fermer geogebra.
 +
* Utiliser le logiciel de décompression de votre choix: <code>unzip boulier.zip</code>
 +
* On se trouve alors (éventuellement dans un sous-dossier boulier) avec 3 fichiers, dont un s'appelle <code>geogebra.xml</code>. C'est ce fichier qu'on va éditer.  Aller dedans et repérer les objets à dupliquer. C'est une structure assez claire, les objets sont des balises xml element et command. Ainsi, pour la définition du point A0, on trouve dans le fichier XML:
 +
<code>
 +
<command name="Point">
 +
<input a0="a_1"/>
 +
<output a0="A_0"/>
 +
</command>
 +
 
 +
<element type="point" label="A_0"> <show object="true" label="false"/> <objColor r="0" g="0" b="0" alpha="0.0"/> <layer val="0"/> <labelMode val="0"/> <animation step="1" speed="1" type="1" playing="false"/> <ggbscript  val="SetValue[ n , If[ y(A_0)==6 , n-500000 , n+500000 ]]"/> <coords x="1.0" y="7.0" z="1.0"/> <pointSize val="9"/> <pointStyle val="0"/>
 +
</element>
 +
 
 +
</code>
 +
 
 +
Interprétation: A0 est un point de l'objet a1 (la tige 1): c'est la balise commande, la définition du point. Puis on a ses propriétés dans la balise élément. Ce qui est intéressant est que son script apparaît en clair, chaque commande étant séparée des autres par un simple espace: c'est la balise <code>ggbscript</code>.
 +
 
 +
Il suffit alors de:
 +
* prendre une grande respiration
 +
* modifier par copier coller le fichier xml: j'ai personnellement créé un nouveau fichier qui ne contient que la tige (points A0 A1 A2 A3 A4); je fais les modifications dans ce fichier que je réinjecte dans le fichier de départ. C'est un peu répétitif mais en utilisant bien le copier coller et la fonction 'remplacer' des éditeurs de texte, ça va assez vite. Ici, il faut remplacer A_ par B_ (puis C_, D_, ...) et veiller aux décalages d'indices.
 +
 
 +
Une fois le fichier XML modifié, recréer le fichier ggb: il suffit de comprimer en zip les trois fichiers de départs, et le tour est joué! Il faut faire très attention, la moindre faute dans le fichier XML rend votre code illisible par geogebra...

Version du 29 octobre 2013 à 23:40

S'éviter des tâches répétitives en éditant le code XML

Objectif

Ce tutoriel est né d'une appliquette qui m'a fait créer une quarantaine de points, tous munis d'un script au clic: il s'agit d'un boulier où l'on peut interagir dans deux sens:

  • On choisit un entier grâce à des boutons et une zone de texte (entier tapé, entier choisi au hasard, entier choisi dans une liste): le boulier affiche alors cet entier.
  • On clique sur les boules du bouliers pour les déplacer, l'entier correspondant s'affiche alors en écriture décimale.

Chaque boule est représentée par un (gros) point muni d'un script; le but de ce tutoriel est de présenter un moyen de rentrer cette quarantaine de scripts sans devenir fou! Un bon éditeur de texte et de la concentration suffisent...

Le boulier présente plein d'avantages pour enseigner la numération en école primaire ou au début du collège: il permet de plus des exercices de calcul mental, et permet d'apprendre à poser les additions et les soustractions. Mais cela revient beaucoup moins cher de disposer d'un boulier geogebra plutôt que d'acheter autant de bouliers que d'élèves! Le boulier choisi est de type Soroban, avec sur chaque tige, 5 boules valant l'unité (en bas) et une boule valant 5 (en haut). Les boules sont activées lorsqu'elles sont poussées contre la barre centrale. Voici le produit fini.

J'ai fait une première version du boulier où les boules étaient gérées par des listes de points. Il est assez facile de déterminer quelles boules doivent être activées en fonction de l'entier à afficher. C'est un peu de manipulation de la division entière. Ce faisant on arrive facilement à coder la première partie de l'interaction: on choisit un entier, on définit quatre listes dépendant de cet entier: les boules du bas activées, les boules du bas désactivées, les boules du haut activées, les boules du haut désactivées. Quelques commandes Séquence permettent d'afficher les points correspondants au bon endroit et le tour est joué (voir la section suivante). Mais coder l'interaction dans l'autre sens (déplacer les boules pour changer l'entier) demande de récupérer, dans un script, sur quel élément d'une liste on a cliqué. Or, j'ai cherché, demandé dans les forums, et sauf erreur de ma part, cette fonctionnalité n'existe pas dans geogebra. Il a donc fallu faire une version où chaque boule est un point indépendant muni d'un script. D'où le problème: comment éditer facilement un grand nombre de scripts, qui se ressemblent tous à des différences d'indice prêt? En l'absence d'une commande 'SoitScript', on est obligés de passer par le menu propriété->scripts et de rentrer tous les scripts un par un, soit un nombre considérable de manipulations à la souris. Il faut être particulièrement zen et patient pour mener cette tâche sans oublier une boule ou sans se tromper sur l'édition d'un script.

Il y a heureusement moyen de modifier un fichier geogebra via un éditeur de texte: on édite en fait un fichier XML à la structure relativement claire. On rentre alors les scripts directement dans le code XML à l'aide de votre éditeur de texte favori, dont vous maîtrisez la fonction 'chercher/remplacer'.

Les sections qui suivent présentent:

  • la mise en place du boulier avec des listes de points
  • l'adaptation, à l'aide de commandes "Exécute" de cette première version pour obtenir des points indépendants.
  • l'édition des scripts via le code XML.

Première mise en place avec des listes de points

La figure ci-dessous illustre le rendu graphique souhaité:

Boulier interactif disposition.png

  • La tige des unités est en x=6, celle des dizaines en x=5, ..., celle des centaines de mille en x=1.
  • Pour les boules du haut: elles sont activées en y=6, désactivées en y=7.
  • Pour les boules du bas: elles occupent les ordonnées entières, de y=0 (contre la barre du bas) à y=4 (contre la barre centrale).

Si n est l'entier à afficher (0 <= n <= 999999) , on peut obtenir sa liste de chiffres par: listechiffres=Retourner[Séquence[Quotient[Reste[n,10^i], 10^(i - 1)], i, 1, 6]].

Liste pour les boules du bas: listebas=Séquence[Reste[Elément[listechiffres, i], 5], i, 1, 6]. Liste pour les boules du haut: listehaut=Séquence[Quotient[Elément[listechiffres, i], 5], i, 1, 6]. Ces listes indiquent, pour chaque tige, combien de boules sont activées en bas et en haut.

Liste des boules du haut: listeptshaut=Séquence[(i, 7- (Elément[listehaut, i])), i, 1, 6]: ainsi les boules du haut sont positionnées soit en (i,7) (pas de boule activée pour la ième tige) soit en (i,6) (boule activée pour la ième tige).

Liste des boules du bas activées : listeptsbas1=Séquence[Séquence[(i, 5-j), j, 1, Elément[listebas, i]], i, 1, 6]: ainsi les boules du bas activées de la ième tige sont placées en (i,4), (i,3), (i,2), (i,1).

Liste des boules du bas désactivées: listeptsbas2=Séquence[Séquence[(i, j-1), j, 1, 4 - Elément[listebas, i]], i, 1, 6]: ainsi les boules du bas désactivées de la ième tige sont placées en (i,0), (i,1), (i,2), (i,3).

La mise en place est terminée, ainsi que l'interaction entier décimal vers boulier: il suffit de changer la valeur de n pour que les boules prennent automatiquement la bonne position: à vous de créer des boutons et zones de textes pour régler n, et de dessiner le boulier. Il reste encore à régler l'interaction dans l'autre sens.

Les limites des scripts pour les listes : recréer la construction avec la commande Exécute

On peut associer un script (au clic, à l'actualisation) à une liste d'objets. Pour, par exemple, un script au clic, l'effet est que le script sera activé dès lors qu'on clique sur un élément de la liste. Mais, sauf erreur de ma part, il n'existe pas de moyen de récupérer dans le script sur quel élément de la liste on a cliqué.

Or, mon idée était que lorsqu'on clique sur une boule (par ex: une boule désactivée du bas), on modifie par script la valeur de n: si cette boule est la première du tas, alors on fait n=n+1 (tige des unités), n=n+100 (tige des centaines), et l'affichage suit automatiquement via les listes dépendantes de n. Mais pour cela il faut savoir:

  • sur quelle tige on a cliqué (indice i des séquences)
  • pour les boules du bas, savoir si on a cliqué sur un élément qu'on peut bouger: celui du bas pour les boules activées, celui du haut pour les boules désactivées.

Je vais donc refaire l'application avec, au lieu de listes, des nombres et points indépendants créés avec la commande Exécute. Cela permet de réutiliser le travail fait avec des listes, mais en créant des points indépendants. Pour faciliter le copier/coller ultérieur sous XML, je crée des noms logiques: la liste de chiffres (listechiffres) devient par n1, n2, n3...par la commande:

  • Exécute[ Séquence[ "n_"+(7-i)+" = Div[ Mod[ n , 10^"+(i)+"] , 10^"+(i-1)+" ]" , i , 1, 6 ]]

La liste du nombre de boules activées en haut devient les nombres nh1, nh2, ... par:

  • Exécute[ Séquence[ "nh_"+i+" = Div[n_"+i+",5]" , i , 1, 6 ]]

La liste du nombre de boules activées en bas devient les nombres nb1, nb2, .... par:

  • Exécute[ Séquence[ "nb_"+i+" = Mod[n_"+i+",5]" , i , 1, 6 ]]
Note : La commande Exécute prend en argument une liste de chaînes de caractères, qu'elle fait exécuter par geogebra. Je suis donc parti d'une commande Séquence initiale, qui crée une liste, j'ai mis entre guillemets son premier argument, j'ai rajouté n= au début, puis à chaque fois que la valeur de i doit apparaître, je brise la chaîne et j'utilise l'opérateur + (concaténation de chaînes).
Note : Il faut faire attention que les commandes arguments de Exécute (donc ce qui est entre guillemets) doivent être en anglais: Quotient est ainsi devenu Div, Reste est devenu Mod. Utiliser le wiki, section commandes, en français pour trouver votre commande, puis changer la langue (menu en haut à droite de la page) pour avoir son nom anglais.

Ces trois commandes créent, au lieu de trois listes de nombres, les nombres n1, n2, ..., nh1, nh2, ..., nb1, nb2, ...

On peut alors placer les boules: dans la version initiale, c'étaient des listes de points, maintenant cela doit être des points indépendants. Je vais d'abord créer la liste de la première tige (centaines de mille), et la dupliquer dans le code XML.

Ces points s'appelleront A0 (boule du haut), A1 ... A4 (boules du bas). Je crée ces 5 points comme points de la tige puis je change leurs valeurs avec SoitValeur.

SoitValeur[A_0,(1,7-nh_1)]

SoitValeur[A_1,(1,Si[nb_1==0,3,4])]

SoitValeur[A_2,(1,Si[nb_1<=1,2,3])]

SoitValeur[A_3,(1,Si[nb_1<=2,1,2])]

SoitValeur[A_4,(1,Si[nb_1<=3,0,1])]

Note : On aurait pu faire ça avec une commande Exécute/Séquence ... mais ça devient barbare! Par ailleurs, pourquoi d'abord créer les points puis les modifier avec SoitValeur, au lieu de les créer directement avec = ? J'ai envie que ces points aient comme définition: point de la tige, et que l'utilisateur ne puisse pas les changer de tige. SoitValeur se contente de modifier la valeur, pas la définition initiale.

Créer les premiers scripts

Je crée alors les scripts de chacun de ces points à la main. J'ai choisi un script par clic, ce qui implique qu'il faut cliquer sur les points et non les déplacer. Je cherche encore un moyen d'empêcher leur déplacement: si on les rend non sélectionnables, on ne peut plus cliquer dessus...

Voici les scripts à rentrer:

  • point A0: SoitValeur[ n , Si[ y(A_0)==6 , n-500000 , n+500000 ]]
  • point A1: SoitValeur[n , Si[y(A_1)==3,n+100000,Si[y(A_1)==4 ∧ y(A_2)==2,n-100000,n] ] ]
  • point A2: SoitValeur[ n , Si[ y(A_2)==2 ∧ y(A_1)==4, n+100000 ,Si[y(A_2)==3 ∧ y(A_3)==1 , n-100000 , n] ] ]
  • point A3: SoitValeur[ n , Si[ y(A_3)==1 ∧ y(A_2)==3, n+100000 ,Si[y(A_3)==2 ∧ y(A_4)==0 , n-100000 , n] ] ]
  • point A4: SoitValeur[ n , Si[ y(A_4)==0 ∧ y(A_3)==2, n+100000 ,Si[y(A_4)==1 , n-100000 , n] ] ]

Ces scripts modifient l'entier n, qui, via le dynamisme des constructions de geogebra, actualise la position des points A0 ... A4.

  • Pour le point A0, l'interaction est simple, si la boule est activée (y(A0)=6), retirer 500000, sinon ajouter 500000.
  • Pour le points suivants, par exemple A2: on vérifie qu'on peut le bouger vers le haut (y(A2)=2 et y(A1)=4)), si oui on augmente n de 100000, sinon on vérifie qu'on peut le bouger vers le bas ( y(A2)=3 et y(A3)=1), si oui on diminue n de 100000, sinon on laisse n inchangé (boule non déplaçable). Il y a un test de moins pour A1 et A4, qui sont des boules qui n'ont qu'un voisin.

Dupliquer à l'aide du code XML

On peut alors ... refaire la même chose pour toutes les tiges (ouf! autant de scripts que de points...) ou essayer de tirer parti de la logique de notation pour appliquer en masse du copier/coller. Une commande 'SoitScript' permettrait d'entrer ces scripts via une commande Exécute et quelques aspirines, mais en l'absence de cette commande, on peut attaquer le code XML. La procédure est la suivante (les commandes sont celles de Linux, mais il suffit d'adapter):

  • Faire une copie du fichier geogebra en fichier zip: cp boulier.ggb boulier.zip et fermer geogebra.
  • Utiliser le logiciel de décompression de votre choix: unzip boulier.zip
  • On se trouve alors (éventuellement dans un sous-dossier boulier) avec 3 fichiers, dont un s'appelle geogebra.xml. C'est ce fichier qu'on va éditer. Aller dedans et repérer les objets à dupliquer. C'est une structure assez claire, les objets sont des balises xml element et command. Ainsi, pour la définition du point A0, on trouve dans le fichier XML:

<command name="Point"> <input a0="a_1"/> <output a0="A_0"/> </command>

<element type="point" label="A_0"> <show object="true" label="false"/> <objColor r="0" g="0" b="0" alpha="0.0"/> <layer val="0"/> <labelMode val="0"/> <animation step="1" speed="1" type="1" playing="false"/> <ggbscript val="SetValue[ n , If[ y(A_0)==6 , n-500000 , n+500000 ]]"/> <coords x="1.0" y="7.0" z="1.0"/> <pointSize val="9"/> <pointStyle val="0"/> </element>

Interprétation: A0 est un point de l'objet a1 (la tige 1): c'est la balise commande, la définition du point. Puis on a ses propriétés dans la balise élément. Ce qui est intéressant est que son script apparaît en clair, chaque commande étant séparée des autres par un simple espace: c'est la balise ggbscript.

Il suffit alors de:

  • prendre une grande respiration
  • modifier par copier coller le fichier xml: j'ai personnellement créé un nouveau fichier qui ne contient que la tige (points A0 A1 A2 A3 A4); je fais les modifications dans ce fichier que je réinjecte dans le fichier de départ. C'est un peu répétitif mais en utilisant bien le copier coller et la fonction 'remplacer' des éditeurs de texte, ça va assez vite. Ici, il faut remplacer A_ par B_ (puis C_, D_, ...) et veiller aux décalages d'indices.

Une fois le fichier XML modifié, recréer le fichier ggb: il suffit de comprimer en zip les trois fichiers de départs, et le tour est joué! Il faut faire très attention, la moindre faute dans le fichier XML rend votre code illisible par geogebra...

© 2024 International GeoGebra Institute