Découvrir Scilab/Créer une interface graphique GUI
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
modifierScilab 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
modifierIl est possible de créer soi-même une interface graphique utilisateur. Cela se fait avec la commande uicontrol
.
Pointeur d'un objet
modifierChaque 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 no 1, la variablef
pointant sur cette figure ;f = scf(0)
: indique que la figure courante est la figure 0, la variablef
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 :
pointeur = uicontrol(...)
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
modifierPour é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 :
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 :
- 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 parfontunit
; - 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"
.
- propriété
Par exemple :
h = gcf();
t = uicontrol(h, "style", "text", ...
"string", "Ceci est <code>une</code> figure", ...
"fontsize", 12, ...
"fontweight", "bold", ...
"fontangle", "italic", ...
"position", [50 70 120 100]);
ou bien
h = gcf();
t = uicontrol(h, "style", "text", ...
"string", "Ceci est <code>une</code> figure", ...
"position", [50 70 120 100]);
set(t, "fontsize", 12);
set(t, "fontweight", "bold");
t.fontangle = "italic";
Créer un bouton
modifierLes 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 :
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
modifierLes 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).
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 :
- par une « chaîne de caractères-raccourci », le paramètre
"g"
de la commandeplot()
; - 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
modifierUne 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é
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 — 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 (pointeure
), la transforme en nombre (« évaluation » de la chaîne) et la place dans la variablex
. 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 variablee
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 champuserdata
du bouton (voir plus loin).y = x^2
: calcule le carré dex
et place le résultat dans la variabley
;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 (pointeurt
) ; cela provoque l'affichage de la valeur.t
est aussi sujet quee
à effacement ou écrasement intermédiaire.plot2d(x, y, style = -1)
: place le point sur le graphique.
Encapsulation dans une fonction
modifierSi 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 :
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 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
modifierLe 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 (n1 et n2), 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
"userdata", [N1, N2, aff_pgcd, aff_ppcm]
avec :
N1
: pointeur vers la première zone d'édition, contenant la valeur n1 ;N2
: pointeur vers la seconde zone d'édition, contenant la valeur n2 ;aff_pgcd
: pointeur vers la zone de texte destinée à afficher PGCD(n1, n2) ;aff_ppcm
: pointeur vers la zone de texte destinée à afficher PPCM(n1, n2).
La fonction d'appel du bouton contient :
n1 = eval(gcbo.userdata(1).string)
: récupération de n1, cargcbo.userdata(1)
est l'équivalent deN1
;n2 = eval(gcbo.userdata(2).string)
: idem pour n2 ;gcbo.userdata(3).string = string(pgcd)
: écrit le contenu de la variablepgcd
dans la chaîne du pointeurgcbo.userdata(3)
qui n'est autre queaff_pgcd
;gcbo.userdata(4).string = string(ppcm)
: idem avec le PPCM.
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);
Voir aussi
modifierNotes
modifier