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 :
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 codice_5. 
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 :
On peut aussi récupérer le pointeur de la fenêtre courante par la commande codice_10 — raccourci de codice_11.
Les objets de l'interface graphique ont eux aussi leur pointeur, dont le nom est défini à la création :
pointeur = uicontrol(...)
Le premier argument de la commande codice_5 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 « codice_13 ». Elles peuvent aussi être définies "a posteriori" avec la syntaxe classique des pointeurs : « codice_14 ».
Écrire dans une figure.
Pour écrire un texte statique, on utilise la propriété codice_15 avec la valeur codice_16.
Pour le texte en lui-même, on utilise la propriété codice_17, 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é codice_18, la valeur étant une vecteur contenant les coordonnées ("x", "y") du point en bas à gauche, et les dimensions ("l", "h") (largeur et hauteur) : codice_19.
Par exemple :
h = figure(0);
t = uicontrol(h, "style", "text", ...
 "string", "Ceci est une figure", ...
 "position", [50 70 100 100]);
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 :
Par exemple :
h = gcf();
t = uicontrol(h, "style", "text", ...
 "string", "Ceci est codice_44 figure", ...
 "fontsize", 12, ...
 "fontweight", "bold", ...
 "fontangle", "italic", ...
 "position", [50 70 120 100]);
ou bien
h = gcf();
t = uicontrol(h, "style", "text", ...
 "string", "Ceci est codice_44 figure", ...
 "position", [50 70 120 100]);
set(t, "fontsize", 12);
set(t, "fontweight", "bold");
t.fontangle = "italic";
Créer un bouton.
Les boutons sont créés avec la propriété codice_15 et la valeur codice_47. 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 :
Exemple :
b = uicontrol("style", "pushbutton"...
 "string", "$x^2$"...
 "callback", "X = [0:0.1:5]; plot(X, X.^2);");
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é codice_51. Puis, nous créons des boutons pour modifier la couleur de la courbe, c'est-à-dire la propriété codice_52.
Notons que nous travaillons avec des unités normalisées (propriétés codice_53) : dans ce système d'unités, la largeur et la hauteur de la fenêtre valent 1. Pour la fonction codice_54, 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).
f = figure(0);
clf;
// la fenêtre de traçage occupe 90 % de la hauteur
// réserve 10 % de la fenêtre en bas pour les boutons
xsetech([0, 0, 1, 0.9])
// tracé de la courbe
X=[0:0.1:5];
plot(X, X.^2, "g"); // courbe verte
composant = gce();
courbe = composant.children;
// bouton changeant la couleur en noir
bnoir = uicontrol("style", "pushbutton"...
 "units", "normalized"...
 "position", [0, 0, 0.1, 0.05]...
 "BackgroundColor", [0,0,0]...
 "callback", "courbe.foreground=1");
// bouton changeant la couleur en rouge
brouge = uicontrol("style", "pushbutton"...
 "units", "normalized"...
 "position", [0.11, 0, 0.1, 0.05]...
 "BackgroundColor", [1,0,0]...
 "callback", "courbe.foreground=5");
Notons également que les couleurs sont définies de trois manières :
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é codice_15 et la valeur codice_60. On peut indiquer le texte initial qu'elle contient avec la propriété codice_17. C'est également par ce biais-là que l'on récupère sa valeur.
Exemple : calcul et tracé de la fonction carré
f = scf(0);
// zone d'édition, saisie de la valeur
e = uicontrol(f, "style", "edit", ...
 "position", [0 0 100 20]);
// zone de texte, affichage du résultat
t = uicontrol(f, "style", "text", ...
 "position", [200 0 100 20], ...
 "string", "...");
// bouton effectuant le calcul
b = uicontrol(f, "style", "pushbutton", ...
 "string", "$x^2$"...
 "position", [100 0 100 20], ...
 "callback", "x = evstr(e.string);" + ...
 "y = x^2;" + ...
 "t.string = string(y);" + ...
 "plot2d(x, y, style = -1);");
Essayer l'exemple en prenant des valeurs successives sans interrompre le programme. Par exemple commencer par des valeurs extrêmes — codice_62 puis codice_63 — pour fixer l'échelle graphique, et « remplir » par des valeurs intermédiaires (codice_64, codice_65, codice_66, …).
Analysons la fonction de rappel :
Encapsulation dans une fonction.
Si l'interface graphique est définie dans une fonction (codice_80), 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é codice_71 pour stocker des données, puis y faire appel avec la variable codice_82 — "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 codice_83, il affiche « 0 » à la place :
function []=test(h)
 texte = uicontrol(h, "style", "edit", ...
 "string", "foo"...
 "fontsize", 14, ...
 "position", [50 100 100 20]);
 bouton = uicontrol(h, "string", "OK"...
 "position", [50 50 50 20], ...
 "userdata", texte, ...
 "callback", "gcbo.userdata.string = string(0);");
endfunction
fig = figure(0);
test(fig);
Lorsque l'on définit le bouton, on enregistre donc le pointeur codice_84 dans la propriété codice_71 du bouton. On peut ensuite faire appel à ce pointeur grâce à la variable codice_86 : codice_87 est l'équivalent de codice_88..
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 codice_71 du bouton est un vecteur de quatre pointeurs : la définition du bouton d'exécution (composant dont le pointeur est codice_90) contient
 "userdata", [N1, N2, aff_pgcd, aff_ppcm]
avec :
La fonction d'appel du bouton contient :
Ce qui nous donne le code source suivant.
//============================================================================
// nom : pgcd_ppcm_euclide_gui.sce
// auteur : Christophe Dang Ngoc Chan
// date de création : 2013-01-02
// dates de modification : ...
// version de Scilab : 5.4.1
// module Atoms requis : aucun
// Objectif : détermine le PGCD et le PPCM par l'algorithme d'Euclide
// Entrées : deux nombre entier (scalaires)
// Sorties : deux nombres entiers (scalaires)
// ***** Fonctions et procédures *****
function [resultat]=euclide(a, b)
 r=modulo(a,b); // initialisation du reste
 while r<>0
 a = b;
 b = r;
 r=modulo(a,b); // calcul du reste
 end
 resultat = b;
endfunction
function []=fenetre_graphique(h)
 // titre de la boîte
 titre = uicontrol(h, "style", "text", ...
 "string", "PGCD et PPCM", ...
 "fontweight", "bold", ...
 "fontsize", 14, ...
 "position", [50 400 120 20]);
 // consignes
 texte_expl = uicontrol(h, "style", "text", ...
 "string", "Entrez deux nombres entiers et cliquez sur [OK]", ...
 "fontsize", 14, ...
 "position", [50 370 300 20]);
 // saisie du 1er nombre
 texte_b1 = uicontrol(h, "style", "text", ...
 "string", "N1 = ", ...
 "fontsize", 14, ...
 "position", [50 340 50 20]);
 N1 = uicontrol(h, "style", "edit", ...
 "string", "1"...
 "fontsize", 14, ...
 "position", [85 340 100 20]);
 // saisie du 2nd nombre
 texte_b2 = uicontrol(h, "style", "text", ...
 "string", "N2 = ", ...
 "fontsize", 14, ...
 "position", [50 310 50 20]);
 N2 = uicontrol(h, "style", "edit", ...
 "string", "1", ...
 "fontsize", 14, ...
 "position", [85 310 100 20]);
 // affichage du PGCD
 texte_res1 = uicontrol(h, "style", "text", ...
 "string", "PGCD = ", ...
 "fontsize", 14, ...
 "position", [50 250 50 40]);
 aff_pgcd = uicontrol(h, "style", "text", ...
 "string", "...", ...
 "fontsize", 14, ...
 "position", [110 250 50 40]);
 // affichage du PPCM
 texte_res2 = uicontrol(h, "style", "text", ...
 "string", "PPCM = ", ...
 "fontsize", 14, ...
 "position", [50 220 50 40]);
 aff_ppcm = uicontrol(h, "style", "text", ...
 "string", "...", ...
 "fontsize", 14, ...
 "position", [110 220 50 40]);
 // bouton d'exécution et fonction de rappel
 bouton = uicontrol(h, "string", "OK"...
 "position", [50 280 50 20], ...
 "userdata", [N1, N2, aff_pgcd, aff_ppcm], ...
 "callback", "n1 = eval(gcbo.userdata(1).string);" + ...
 "n2 = eval(gcbo.userdata(2).string);" + ...
 "pgcd = euclide(n1, n2);" + ...
 "ppcm = n1*n2/pgcd;" + ...
 "gcbo.userdata(3).string = string(pgcd);" + ...
 "gcbo.userdata(4).string = string(ppcm);");
endfunction
// ***** Programme principal *****
fig = figure(0); // création de la fenêre
clf;
fenetre_graphique(fig);
Notes.
"Programmation" < ↑ > "Environnement"