Baniere Saphir Control
http://www.saphir-control.fr/

bar


BACK

Scilab : un logiciel libre pour le calcul scientifique
9e Partie - L'interface utilisateur

Matthieu PHILIPPE (Saphir Control)



Tous ces articles en ligne sur Scilab ont été écrits pour LINUX MAGAZINE FRANCE par les développeurs du Scilab Group. Les articles sont sous licence FDL (Free Documentation Licence)



Vous avez eu dans les deux précédents numéros une description de la toolbox Scicos. Scicos a été entièrement écrit en langage Scilab, aussi bien les calculs, que la gestion graphique des blocs et des menus. Nous allons voir dans cet article les primitives nécessaires pour construire une interface utilisateur.

1   Les primitives graphiques

Scilab permet de tracer toutes sortes de graphiques. Bien qu'il existe des fonctions de haut niveau et très puissantes, nous ne verrons dans cet article que les primitives de base.

Dans cette section, vous apprendrez à déterminer des zones de travail, dessiner un rectangle, des lignes, des flèches, des arcs et des ellipses. Rappelons que pour une aide sur une fonction, par exemple xclick, vous pouvez taper dans la fenêtre Scilab l'une des commandes suivantes :
-->apropos xclick
 
-->help xclick

1.1   Fenêtre graphique et changement d'origine

Avant tout regardons comment obtenir les dimensions d'une fenêtre graphique donnée. Il suffit de taper :
-->[wrect,frect]=xgetech()
 frect  =
 
!   0.    0.    1.    1. !
 wrect  =
 
!   0.    0.    1.    1. !
qui renvoit dans wrect (Working RECTangle) un quadruplet [x,y,w,h] contenant les coordonnées (x,y) du coin supérieur gauche et les proportions (w,h) de la zone de travail (w est la largeur et h la hauteur). Ce sont les proportions relatives à la taille courante de la fenêtre. L'échelle de proportion dans cette zone de travail est donnée par frect (Frame RECTangle), un quadruplet [xmin, ymin, xmin, xmax].

Pour redéfinir la zone par défaut, nous utilisons l'instruction xsetech( wrect, [frect[, logflag]]) qui permet de redéfinir l'échelle de la fenêtre graphique, ainsi que son origine. Par exemple :
--> wrect=[0.5,0,0.5,1]
--> xsetech(wrect);
signifie que seule la moité droite de la fenêtre sera affectée.
Pour définir l'échelle entre (-10 ; 10) pour l'axe des ordonnées et (-10 ; 10) pour les abscisses sur toute la fenêtre entrons la suite d'instructions :
--> wrect=[0,0,1,1];       // on selectionne toute la fenetre

--> frect=[-10 -10 10 10]; // definition de l'\'echelle 

--> xsetech(wrect,frect) ;

1.2   Dessiner un rectangle

Nous pouvons alors dessiner un rectangle dans un repère orienté grâce à l'instruction xrect(x, y, w, h), par exemple le rectangle d'origine (0,0) et de dimension (7,7), après changement de l'échelle de la fenêtre courante :
-->wrect=[0 0 1 1];

-->frect=[-10 -10 10 10];

-->xsetech(wrect,frect); // definition de l'\'echelle

-->xarrows([0 0],[-10 10],0.5); 
     // dessine les axes sous forme de fleches
 
-->xarrows([-10 10],[-0 0],0.5);

-->xrect(0 ,0 ,7 ,7);

Affichons un rectangle de coins supérieur gauche (x0=0,y0=6) et inférieur droit (x1=5, y1=0) :
-->green = 3;xset("foreground",green);xrect(0, 6, 5,6);//w=x1-x0 et h=y1-y0
La variante xfrect dessine un rectangle plein (f comme filled) en utilisant la couleur définie par xset. xrects dessine un ensemble de n rectangles (s pour plusieurs rectangles), dont les quadruplets sont sous la forme d'une matrice 4 lignes et n colonnes (4xn). Devinez ce que fait xfrects !

-->xrects([[0 ;0 ;7 ;7], [0; 6; 5;6]], [-1 2])

{short description of image}

Figure 1:

Remarquez qu'un indice de couleur positif rempli le rectangle, un indice négatif dessine le contour.

1.3   Dessiner des lignes et flèches

La syntaxe générale de la fonction xarrows que nous avons utilisée dans l'exemple précédent est xarrows( nx, ny, [ size, style]). Les paramètres nx est une matrice 2xn contenant les abscisses des points de départ et d'arrivée, ny les ordonnées. Ainsi, l'affichage des deux axes s'effectue par une seule instruction.

-->xarrows([0 -10; 0 10], [-10 0; 10 0],...
      0.5, [3 4]);
Pour dessiner une ligne brisée (un ensemble de segments reliés), Scilab propose l'intruction :

xpoly(xv, yv, dtype, [closeflag])xv et yv sont respectivement les n-uplets des abscisses et des ordonnées, la chaîne de caractères dtype est soit ``lines'' soit ``marks'', et closeflag est un entier positionné à 1 pour obtenir une forme fermée, et différente de 1 pour une forme ouverte :
-->  xpoly([1 4 8],[ 1 2 10],"lines",0); // polygone ouvert
 
-->  xpoly([-1 -4 -8],[ -1 -2 -10],"lines",1); // polygone ferme

{short description of image}

Figure 2: Polyline.

1.4   Dessiner des Arcs et des Cercles

L'instruction xarc(x,y,w,h,angle_debut,angle_de_rotation) dessine un arc contenu dans le rectangle défini par (x,y,w,h). La fonction xarc utilise des angles exprimés en 64ième de degré. Les instructions suivantes dessinent un quart de cercle (un arc de 90o à partir de 90o) inscrit dans le rectangle :
-->xrect(0,0,5,5);

-->xset("pattern",2)
 
-->xfarc(-8,8,16,16,90*64,90*64);

{short description of image}

Figure 3: Arc plein.

Il existe les mêmes variantes que pour xrect : xfarc, xarcs et xfarcs. Par exemple :
-->arcs=[-8 0 0.5;               // coin superieur gauche x
-->         8 0.0 0.5;           // coin superieur gauche y
-->         0.5 1.0 0.5;         // largeur
-->         0.5 0.5 1.0;         // hauteur
-->         0.0 0.0 0.0;         // angle de depart
-->         180*64 360*64 90*64];// angle de rotation
-->xarcs(arcs,[1,2,3]);// trois arcs de trois couleurs differentes

2   Interfaces utilisateur

Pour permettre le développement d'outils graphiques interactif, Scilab propose quelques fonctions de base. Ces fonctions permettent à l'utilisateur de détecter des évènements, de définir des fenêtres de dialogue et de gérer des menus.

2.1   Détection des évènements souris et du clavier

Les trois fonctions xclick, xgetmouse et locate permettent de connaître la position de la souris dans une fenêtre graphique et de détecter les évènements de la souris et du clavier. Ce sont des fonctions bloquantes. C'est-à-dire que leur appel bloque l'interpréteur Scilab, jusqu'à ce qu'une action de la souris ait été réalisée.

La fonction xclick attend un clic de la souris ou l'appui d'une touche du clavier. Sa syntaxe est [mouse_button, x_coordinate, y_coordinate, gwin_num, callback_string]=xclick([flag]) . Les variables renvoyées sont :
-->[button, x, y, gwin, str]=xclick();
    //j'appuie sur le bouton gauche de la souris
    //dans la fenetre graphique 0
 str  =
 
 void   
 gwin  =
 
    0.  
 y  =
 
  - 1.4615385  
 x  =
 
  - 12.138085  
 button  =
 
    0.  
--> [button, x, y, gwin, str] = xclick();
     // j appuie sur a dans la fenetre 
     // graphique 0    
 str  =
 
 void
 gwin  =
    0.
 y  =
  - 12.923077
 x  =
  - 11.113586
 button  =
    97.
L'instruction rep=xgetmouse([flag]), renvoit la position de la souris dans la fenêtre courante. Si flag est présent les clics sont mémorisés dans la queue d'évènements et ne sont pas effacés lors de l'appel à xgetmouse. Cette fonction renvoit un vecteur rep=[x y bouton], dans lequel x et y représentent la position de la souris en coordonnées utilisateurs (cf. xsetech), et bouton est un entier égal à 0, 1 ou 2 selon le bouton de souris cliqué, -1 s'il s'agit d'un mouvement de souris. Contrairement à xclick, xgetmouse n'attend pas de clic de souris ou de touche clavier. Il permet ainsi de connaître à tout moment la position de la souris.
-->a=xgetmouse();//je place la souris sur la fenetre
 a  =
 
! - 8.5746102  - 8.6923077  - 1. !

-->a=xgetmouse();//je clic sur le bouton gauche
 a  =
 
! - 1.8040089    1.3846154    0. !

-->while(1)

-->rep=xgetmouse() 
       //renvoit dans la fenetre courante 
       //la position de la souris
       // lors de son deplacement
-->end;
L'instruction locate([n[,flag]]) renvoit la matrice des points selectionnés par un clic. Si n est supérieur à 0, alors n points devront être impérativement selectionnés. Si n est égal à -1, les points sont selectionnés par le bouton droit ou milieu jusqu'à ce que le bouton gauche ait été cliqué. Si flagest égal à 1, alors une croix est placée à chaque coordonnée selectionnée.
-->a=locate(3,1);//je clic 3 fois et dessine 3 croix
 a  =
 
! - 5.2783964  - 1.3585746  - 5.6347439 !
!   10.615385    10.153846    6.7692308 !

2.2   Boîtes de dialogues

2.2.1   x_dialog

L'instruction result=x_dialog(labels,valueini) crée une boîte de dialogue utilisateur. Le paramètre labelsest un vecteur de chaîne de caractères qui spécifit le titre de la fenêtre puis le titre de la saisie, et valueini initialise la valeur par défaut. La fonction renvoit la valeur saisie qui peut être un scalaire ou une chaîne de caractères, ou alors la matrice vide [] si le bouton Cancel est appuyé.

-->x_dialog(['Taille';'entrez la taille';'un autre commentaire'],'1')
 ans  =
 
 1

{short description of image}

Figure 4: Boîte de dialogue.

2.2.2   x_mdialog

Les instructions result=x_mdialog(titre, labels, valeur_initiale) ou result=x_mdialog(titre,label_vertical,label_horizontal,matrice_valeur_initiale) permettent de saisir des matrices de chaînes de caractères.
 -->x_mdialog('matrice',['L 1'; 'L 2'],['C 1' ;'C 2'],['a','b';'c', 'd'])
 ans  =
 
!a  b  !
!      !
!c  d  !

Pour convertir les chaînes de caractères en valeurs numériques vous pouvez utiliser la fonction evstr sur les éléments de la matrice.

{short description of image}

Figure 5: Boîte de dialogues multiples.

2.2.3   x_choose

L'instruction num=x_choose(labels, titre [,bouton]) permet de choisir un item parmi les labels. La fonction renvoit le numéro de l'item choisi, 0 si Cancel.
-->  n=x_choose(['item1';'item2';'item3'],['ceci est un commentaire'])
 n  =        
 
    2.  

{short description of image}

Figure 6: Boite de choix.

2.2.4   getvalue

La fonction de haut niveau getvalue encapsule x_dialog et petrmet de saisir des valeurs avec détection d'erreurs, évaluation de la réponse.... Sa syntaxe est [ok,x1,..,x14]=getvalue(titre, labels, type, init) où la chaîne de caractère titre contient le nom de la boîte , labels correspond aux noms des champs à saisir, type est une list Scilab qui définit le type et le nombre d'éléments de chaque champs par list(typ1,dim1,..,typn,dimn)typn est l'une des ces chaînes de caractères : dim un scalaire supérieur à zéro, ou égal à -1 si la dimension est indéfinie. init est le vecteur de valeurs initiales. ok vaut %t (true) si le bouton Ok a été appuyé ou %f (false) si Cancel a été appuyé. xi contient la valeur de retour de chacun des champs.
-->  labels=["magnitude";"frequence";"phase    "];
-->  [ok,mag,freq,ph]=getvalue("definit le signal sinus",labels,...
-->       list("vec",1,"vec",1,"vec",1),["0.85";"10^2";"%pi/3"])
 ph  =
 
    1.0471976  

 freq  =
 
    100.  
 mag  =
 
    0.85  
 ok  =
 
  T  

{short description of image}

Figure 7: Boite de dialogue évoluée.

2.3   La gestion des menus

Dans cette section nous allons construire des exemples de menus simples.

2.3.1   Ajouter un menu

Pour créer un menu nous utilisons l'instruction : addmenu(gwin,menu_name [,submenus] [,action]). Cette intruction permet d'ajouter un menu dans une fenêtre Scilab, désignée par son numéro gwin. Signalons que gwin=-1 désigne la fenêtre principale (comme le racourci addmenu(menu_name [,submenus] [,action])). Le paramtre menu_name est une chaîne de caractères représentant le label du bouton. Par exemple :
--> menu_name = 'Dessin';
submenus est un vecteur de chaîne de caractères désignant les labels des sous-menus. Par exemple :
 
--> submenus = ['Rectangle';'Ligne';'Cercle']
actionest une liste(cf. Linux Magazine numéro 14) de deux éléments : action=list(flag,proc_name), où flag est un entier. Lorsqu'il est mis à 0, sa valeur par défaut, action est une chaîne de caractère nommant soit une variable (qui contient une suite d'instructions Scilab) soit une fonction Scilab. Le cas flag=1 est réservé à l'appel d'une routine externe C ou FORTRAN. Par exemple :
 
--> action = list(0,'Dessin');
proc_name est la chaîne de caractères désignant ``Dessin'' tel que les callbacks du menu Dessin soient des chaînes de caractères ordonnées dans un tableau
proc_name_numero_de_fenêtre_graphique(numéro_de_sous-menu), pour un bouton dans la fenêtre de command la syntaxe est proc_name(numéro_de_sous-menu). Remarquez le _0 à la fin du nom de la procédure Dessin. Il s'agit du numéro de fenêtre graphique (gwin) à laquelle est associé le bouton. Si le bouton appartient à la fenêtre principale, il n'y a pas de postfixe à ajouter. :
 
-->Dessin_0(1) = 'xrects([-1; 1 ;3; 3])';
    //premier sous-menu de la fenetre 0

-->addmenu(0, menu_name, submenus, action);
Remarquez le _0 à la fin du nom de la procédure Dessin. Il s'agit du numéro de fenêtre graphique (gwin) à laquelle est associé le bouton.

2.3.2   Désactiver et réactiver un menu

Il est parfois nécessaire de bloquer l'utilisation d'un menu ou d'un sous-menu. Ces fonctionnalités sont accessibles par les instructions unsetmenu(gwin,menu_name,[nsub]) et setmenu(gwin,menu_name,[nsub]). Dans ces instructions, le paramètre nsub identifie le nième label du sous-menu qui doit être désactivé. Ainsi l'instruction
 
--> unsetmenu(0,'Dessin');
désactive le menu Dessin, alors que
 
--> unsetmenu(0,'Dessin',1)
ne désactive que le menu Dessin/Rectangle en laissant actifs Dessin/Ligne et Dessin/Cercle.


{short description of image}

Figure 8: Désactivation de Dessin/Rectangle.

Bien sûr on peut les réactiver par la fonction setmenu. Les paramètres d'appel de cette fonction sont identiques à celle de unsetmenu. L'exemple suivant :
 
--> setmenu(0,menu_name);
active le menu Dessin, alors que
 
--> setmenu(0,menu_name,1)
active de nouveau le menu Dessin/Rectangle.

2.3.3   Supprimer un menu

La suppression de n'importe quel menu, même ceux existant par défaut, se fait par l'instruction delmenu(menu_name) et delmenu(gwin,menu_name).
 
--> delmenu(menu_name);

2.4   Interface avec TCL/TK

Enfin vous pouvez développer vos propres interfaces en langage TK grâce aux fonctions TK_EvalStr, TK_EvalFile, TK_GetVar, TK_Setvar. La fonction TK_EvalStr évalue une chaîne de caractères contenant une instruction TK; TK_EvalFile exécute un fichier TK; TK_GetVar, TK_Setvar permettent de positionner les valeurs de variables TK.

3   Une petite application

Nous allons réaliser une petite application qui affichera des rectangles, des cercles, des lignes brisée ou des flèches dans une fenêtre graphique, par l'intermédiaire d'un menu. Vous trouverez sur le CD de login le code complet de l'exemple, ou en cliquant ici sources.


{short description of image}

Figure 9: Un petit programme.

function [a]=graph()

STOP = 0; // variable me permettant de boucler dessus

//affichage d'une nouvelle fenetre
disp('creation d''une nouvelle fenetre') ;
gwin = (max(winsid())+1);// genere un nouveau numero de fenetre
xset('window',gwin);// affiche la nouvelle fenetre

// nouveaux coordonnees utilisateur
xsetech([0 0 1 1],[-10 -10 10 10]);

// ajout des menus de dessins

// definition du nom du menu
Nom_de_Menu = 'Dessin';

// definition des sous-menus
Sub_Menu    = ['Rectangle';'Polyline';'Fleche';'Cercle'];

// definition du type de fonctions associees au menu Dessin
Action      = list(0,'Dessin');

// definition du vecteur de callbacks
execstr('Dessin_' + string(gwin) + '= [''Rec()''; ''Poly()''; ...
           ''Fleche()''; ''Cercle()'']');

addmenu(gwin, Nom_de_Menu, Sub_Menu,Action);

//ajout de menu d'arret
addmenu(gwin,'Stop');
execstr('Stop_' + string(gwin) + '= ''STOP = 1''');

//boucle infinie
while (STOP == 0)
end;
a= 0;

// fonction de dessin du rectangle
function Rec()
  xset("alufunction",6);//nous passons en mode xor
  xinfo(" drawing a rectangle ");//nous affichons de l'information
  [b,x0,y0]=xclick(); 
  rep=[x0,y0,-1]; 
  x=x0; // au depart les coordonnees
  y=y0; // sont confondues
  xrect(x0,y0,x-x0,y-y0); // on affiche une premiere fois
                          // un rectangle
  while rep(3)==-1 then
      rep=xgetmouse(0);
      if (rep(3) ~= 2) then 
        xrect(min(x,x0),max(y,y0),abs(x-x0),abs(y0-y));
                // on efface l'acien rectangle
        x=rep(1); y=rep(2); // on affiche le nouveau
        xrect(min(x,x0),max(y,y0),abs(x-x0),abs(y0-y));
      else
        xrect(min(x,x0),max(y,y0),abs(x-x0),abs(y0-y));
      end;
  end;
  xset("alufunction",3);//nous repassons en mode normale

// fonction de dessin de la ligne bris\'ee
function Poly()
  xset("alufunction",6);//nous passons en mode xor
  xinfo(" cliquez avec le bouton droite ou du milieu...
  Bouton de gauche pour arreter ");//nous affichons de l'information
  a=locate(-1,1);// nous definissons les points a relier
    xpoly(a(1,:),a(2,:),"lines")
  xset("alufunction",3);
Pour pouvoir manipuler ultèrieurement les objets graphiques que vous venez de construire, vous pouvez sauvegarder leurs caractéristiques et leurs coordonnées en utilisant des list (cf lm14).

Voila, vous avez maintenant tout loisir de développer toutes sortes d'interfaces utilisateurs Scilab, pour faciliter la saisie de vos futurs programmes, ou peut-être de nouvelles contributions que nous nous ferons le plaisir d'héberger sur le site Web de Scilab.



Matthieu PHILIPPE
www.saphir-control.fr
scilab@saphir-control.fr
Scilab Group
scilab@inria.fr
http://www-rocq.inria.fr/scilab/
Newsgroups: comp.soft-sys.math.scilab


This document was translated from LATEX by HEVEA.