# Découvrir Scilab/Créer une interface graphique GUI

Table des matières — Index
13. Créer une interface graphique GUI
Jusqu'ici, nous avons interagit avec notre programme Scilab via la ligne de commande. Il est également possible d'utiliser une interface graphique utilisateur (UI : user interface, ou GUI : graphical user interface).
Rappelons-le : le fait de disposer d'une interface graphique est peut-être une fonctionnalité importante du script, notamment si celui-ci doit être utilisé par un « non-spécialiste », mais la priorité — en terme de délais et de moyens — est de faire un programme qui calcule juste ! On commence donc par réaliser un programme avec une interface peu attractive, et l'interface graphique est réalisée en dernier, lorsque tout le reste fonctionne.

## Interface graphique préprogrammée

Scilab propose quelques fonctions permettant une interaction via une interface graphique utilisateur :
* nom_chemin = uigetdir : ouvre une boîte de dialogue permettant de sélectionner un répertoire (dossier, chemin d'accès) ;
* nom_fichier = uigetfile : ouvre une boîte de dialogue permettant de sélectionner un fichier ;
* nom_fichier = uiputfile : ouvre une boîte de dialogue permettant de définir un nom fichier (en vue de le créer ou le modifier) ;
* editvar nom_de_variable : permet de modifier une variable.

## Création d'une interface graphique utilisateur

Il est possible de créer soi-même une interface graphique utilisateur. Cela se fait avec la commande uicontrol.

### Pointeur d'un objet

Chaque composant de l'interface graphique — widget : texte, bouton, curseur, liste déroulante, … — est désigné par un pointeur (handle, littéralement « poignée »). Le pointeur est une variable créée automatiquement par Scilab lors de la création du composant.
La fenêtre graphique (figure) elle-même est désignée par un pointeur. Le nom du pointeur peut être défini lors de la création de la fenêtre, par exemple :
* f = figure(1) : crée la fenêtre graphique n$^o$ 1, la variable f pointant sur cette figure ;
* f = scf(0) : indique que la figure courante est la figure 0, la variable f pointant sur cette figure.
On peut aussi récupérer le pointeur de la fenêtre courante par la commande f = gcf — raccourci de f = get("current_figure").
Les objets de l'interface graphique ont eux aussi leur pointeur, dont le nom est défini à la création :
Le premier argument de la commande uicontrol est normalement le pointeur de la fenêtre graphique concernée. Les propriétés de l'objet peuvent être définies à la création dans la commande sous la forme d'un couple « propriété, valeur ». Elles peuvent aussi être définies a posteriori avec la syntaxe classique des pointeurs : « pointeur.propriété = valeur ».

### Écrire dans une figure

Pour écrire un texte statique, on utilise la propriété "style" avec la valeur "text".
Pour le texte en lui-même, on utilise la propriété "string", la valeur étant le texte à insérer. Pour la mise en forme, on peut utiliser du code HTML ou bien inclure des formules mathématiques en LaTeX.
Pour définir la taille et l'emplacement de la zone de texte, on utilise la propriété "position", la valeur étant une vecteur contenant les coordonnées (x, y) du point en bas à gauche, et les dimensions (l, h) (largeur et hauteur) : [x y l h].
Par exemple :
Ce script crée une zone de texte, située en (50, 70), et ayant pour dimension 100 × 100, et contenant le texte « Ceci est une figure ».
On peut définir la fonte utilisée :
* police : propriété "fontname", la valeur étant le nom de la police ;
* graisse : propriété "fontweight", avec les valeurs "light", "normal" (valeur par défaut), "demi" ou "bold" (gras) ;
* corps : propriété "fontsize", avec la taille de corps en points (scalaire), ou en unité définie par fontunit ;
* unité pour le corps : propriété "fontunit", avec les valeurs "points" (par défaut), "pixel" ou "normalized" ;
* inclinaison : propriété "fontangle", avec les valeurs "normal" (par défaut), "italic" ou "oblic" ;
* alignement :
** propriété "HorizontalAlignment", avec les valeurs "left", "center" (par défaut) ou "right",
** propriété "VerticalAlignment", avec les valeurs "top", "middle" (par défaut) ou "bottom".
Par exemple :
ou bien

### Créer un bouton

Les boutons sont créés avec la propriété "style" et la valeur "pushbutton". C'est par ailleurs le style par défaut, on peut donc omettre de déclarer la propriété.
Les propriétés du bouton sont :
* "string", "..." : texte dans le bouton ;
* "position", "[...]" : position et taille du bouton ;
* "callback", "code scilab" : fonction de rappel (instructions à exécuter lorsque l'on clique).
Exemple :

### Modifier les propriétés d'un élément

Les pointeurs permettent de définir les propriétés d'un élément graphique. Ainsi, une fonction de rappel (callback) peut modifier un autre objet.
Dans l'exemple ci-dessous, nous traçons une courbe en vert ; le pointeur de cette courbe est appelé courbe. Puis, nous créons des boutons pour modifier la couleur de la courbe, c'est-à-dire la propriété courbe.foreground.
Notons que nous travaillons avec des unités normalisées (propriétés "units", "normalized") : dans ce système d'unités, la largeur et la hauteur de la fenêtre valent 1. Pour la fonction xsetech, le point (0, 0) se trouve en haut à gauche, le point (1, 1) en bas à droite (sens de lecture latin). Pour la définition des autre objets, et notamment des boutons que l'on crée, le point (0, 0) est en bas à gauche et le point (1 ,1) en haut à droite (convention mathématique).
Notons également que les couleurs sont définies de trois manières :
* par une « chaîne de caractères-raccourci », le paramètre "g" de la commande plot ;
* par un vecteur RVB, dans la propriété "BackgroundColor" des boutons ;
* par le numéro de la couleur dans carte de couleurs (colormap), pour la fonction de rappel "callback" des boutons.
Le seul point ambigu est le dernier, puisque la carte de couleurs peut changer. Au sein d'un programme, il faut donc s'attacher à maîtriser la carte de couleurs (voir Graphiques et sons > Cartographie couleur).

### Créer une zone d'édition

Une zone d'édition est créée avec la propriété "style" et la valeur "edit". On peut indiquer le texte initial qu'elle contient avec la propriété "string". C'est également par ce biais-là que l'on récupère sa valeur.
Exemple : calcul et tracé de la fonction carré
Essayer l'exemple en prenant des valeurs successives sans interrompre le programme. Par exemple commencer par des valeurs extrêmes — 0 puis 10 — pour fixer l'échelle graphique, et « remplir » par des valeurs intermédiaires (2, 5, 7, …).
Analysons la fonction de rappel :
* x = evstr(e.string) : récupère la chaîne de caractères de la zone d'édition (pointeur e), la transforme en nombre (« évaluation » de la chaîne) et la place dans la variable x. On prendra toutefois garde au fait qu'au moment où le script sera exécuté (lorsque le bouton sera pressé, possiblement longtemps après la création des composants interactifs), la variable e peut ne plus exister. Pour conserver l'"adresse" de la zone d'édition en zone sûre, on peut par exemple la sauvegarder dans le champ userdata du bouton (voir plus loin).
* y = x^2 : calcule le carré de x et place le résultat dans la variable y ;
* t.string = string(y) : transforme la valeur en chaîne de caractère, et place le résultat dans la chaîne de caractères de la zone de texte (pointeur t) ; cela provoque l'affichage de la valeur. t est aussi sujet que e à effacement ou écrasement intermédiaire.
* plot2d(x, y, style = -1) : place le point sur le graphique.

## Encapsulation dans une fonction

Si l'interface graphique est définie dans une fonction (function … endfunction), alors la fonction crée les composants de l'interface grapique (wigets) puis se termine. Lorsque l'on utilise les éléments de l'interface graphique, nous ne sommes donc plus dans l'environnement de la fonction, ce qui pose des problèmes ; en particulier, les pointeurs n'existent plus.
Pour gérer ces problèmes, on peut utiliser la propriété userdata pour stocker des données, puis y faire appel avec la variable gcbo — get callback object, c'est une variable créée automatiquement par Scilab lors de l'exécution dans la fonction de rappel callback).
Par exemple, le petit programme suivant affiche « foo », et lorsque l'on clique sur le bouton [OK], il affiche « 0 » à la place :
Lorsque l'on définit le bouton, on enregistre donc le pointeur texte dans la propriété userdata du bouton. On peut ensuite faire appel à ce pointeur grâce à la variable gcbo.userdata : gcbo.userdata.string est l'équivalent de texte.string..

## Exemple

Le script suivant reprend l'exemple du calcul du PGCD et du PPCM par l'algorithme d'Euclide. Comme nous avons voulu encapsuler la création de la fenêtre graphique dans une fonction (bonne pratique), il nous faut sauvegarder les pointeurs contenant les données dynamiques (qui varient lors de l'exécution). Comme il y a quatre pointeurs — deux variables d'entrée (n$_1$ et n$_2$), et deux variables de sortie (PGCD et PPCM) —, le champ userdata du bouton est un vecteur de quatre pointeurs : la définition du bouton d'exécution (composant dont le pointeur est bouton) contient
avec :
* N1 : pointeur vers la première zone d'édition, contenant la valeur n$_1$ ;
* N2 : pointeur vers la seconde zone d'édition, contenant la valeur n$_2$ ;
* aff_pgcd : pointeur vers la zone de texte destinée à afficher PGCD(n$_1$, n$_2$) ;
* aff_ppcm : pointeur vers la zone de texte destinée à afficher PPCM(n$_1$, n$_2$).
La fonction d'appel du bouton contient :
* n1 = eval(gcbo.userdata(1).string) : récupération de n$_1$, car gcbo.userdata(1) est l'équivalent de N1 ;
* n2 = eval(gcbo.userdata(2).string) : idem pour n$_2$ ;
* gcbo.userdata(3).string = string(pgcd) : écrit le contenu de la variable pgcd dans la chaîne du pointeur gcbo.userdata(3) qui n'est autre que aff_pgcd ;
* gcbo.userdata(4).string = string(ppcm) : idem avec le PPCM.
Ce qui nous donne le code source suivant.

## Notes

Programmation < ↑ > Environnement