8. Interfaces-utilisateur graphiques (GUI)

Ce chapitre est dédié à Danièle ♥ 28.4.2016 ☆

MATLAB ainsi qu'Octave GUI (pour ce dernier depuis la version 4) offrent la possibilité de programmer avec beaucoup de facilité, au-dessus des applications que l'on développe, de véritables interfaces-utilisateur graphiques (GUI, Graphical User Interface). Nous présentons dans ce chapitre :

8.1 Widgets

Le terme "widget" vient de la contraction des mots window gadget.

Widgets (éléments de GUI)


15:35 min
Dans les précédentes vidéo, nous avons présenté la manière d'interagir entre un programme MATLAB/Octave et l'utilisateur via la fenêtre de commande, avec notamment les fonctions disp et input.
Il est cependant possible d'implémenter une interaction MATLAB/Octave de plus haut niveau et plus conviviale, basée "interface-utilisateur graphique" (en anglais "Graphical User Interface", abrégé GUI) :
• cela peut se faire par une véritable programmation événementielle, avec des "contrôles graphiques" (tels que des menus, boutons, champs de saisie etc.) et des fonctions de "callback"... mais cette technique fera l'objet d'une autre vidéo
• cela peut aussi se faire plus simplement en utilisant des "widgets" (contraction de window gadgets), c'est-à-dire des fenêtres de dialogue simples (bouton oui/non/annuler, choix dans une liste, sélection d'un fichier, etc...) ; ce sont les fonctions de base, permettant d'implémenter ces fenêtres de dialogue, que nous présenterons dans la présente vidéo.

8.1.1 Fenêtre de sélection de fichiers et répertoires

[file_name, path] = uigetfile('filtre' {,'titre_dialogue'} )
Fait apparaître à l'écran une fenêtre graphique de dialogue standard de désignation de fichier (selon figures ci-dessous). Fonction utilisée pour désigner un fichier à ouvrir en lecture, en suite de laquelle on utilise en principe la fonction fopen... Une fois le fichier désigné par l'utilisateur (validé par bouton Ouvrir ou OK), le nom du fichier est retourné sur la variable file_name, et le chemin d'accès complet de son dossier sur la variable path. Si l'utilisateur referme cette fenêtre avec le bouton Annuler ou Cancel, cette fonction retourne file_name = path = 0
• La chaîne titre_dialogue s'inscrit dans la barre de titre de cette fenêtre
• Le filtre permet de spécifier le type des fichiers apparaissant dans cette fenêtre. Par exemple *.dat ne présentera que les fichiers ayant l'extension .dat (à moins que l'utilisateur ne choisisse All files (*.*) dans le menu déroulant Fichiers de type:)

Ex: le code ci-dessous fait désigner par l'utilisateur un fichier, puis affiche son contenu
(pour les fonctions fopen, feof, fgetl, fprintf et fclose, voir le chapitre "Entrées-sorties formatées")

[fichier, chemin] = uigetfile('*.dat','Choisir le fichier à ouvrir :');
if ~fichier
   error('Aucun fichier n''a été désigné !')
end

fid = fopen([chemin fichier], 'rt');  % entre crochets, concaténation du chemin et du nom de fichier
while ~ feof(fid)
    ligne = fgetl(fid);
    disp(ligne)
end
status=fclose(fid);

Fenêtre uigetfile sous Windows 7 Fenêtre uigetfile sous Ubuntu/Unity
(remarquez la case à cocher "Preview" et la zone correspondante)

[file_name, path] = uiputfile('fname' {,'titre_dialogue'} )
Fait apparaître une fenêtre de dialogue standard de sauvegade de fichier (en suite de laquelle on fait en principe un fopen...). Le nom de fichier fname sera pré-inscrit dans la zone "Nom de fichier" de cette fenêtre. De façon analogue à la fonction uigetfile, le nom de fichier défini par l'utilisateur sera retourné sur la variable file_name, et le chemin complet d'accès au dossier sélectionné sur la variable path. Si un fichier de même nom existe déjà, MATLAB/Octave demandera une confirmation d'écrasement.

Ex: [fichier, chemin] = uiputfile('resultats.dat','Sauver sous :');

path = uigetdir( {'path_initial' {,'titre_dialogue' } } )
Fait apparaître à l'écran une fenêtre graphique de dialogue standard de sélectionnement de répertoire, et retourne le chemin de celui-ci sur path
• Le path_initial permet de positionner la recherche à partir du path ainsi spécifié. Si ce paramètre est omis, le positionnement initial s'effectue sur le répertoire courant
• La chaîne titre_dialogue s'inscrit dans la barre de titre de cette fenêtre

8.1.2 Fenêtres de dialogue standards

Les fonctions présentées ici permettent d'afficher des fenêtres de dialogues standards. Sauf mention du contraire, elles sont "modale", c'est-à-dire que le programme est suspendu tant que l'utilisateur n'a pas répondu à la sollicitation de la fenêtre.

Nous les présentons sous forme d'exemples, et les illustrations proviennent ici de Octave sous Windows 7.

Fenêtre d'information :

msg={'Message d''information', 'sur plusieurs lignes'};
msgbox(msg, 'Titre fenetre', 'none'); 

Le premier paramètre msg peut être une chaîne simple (qui sous Octave peut contenir \n pour générer un saut à la ligne) ou un vecteur cellulaire de chaînes (chaque élément étant alors affiché dans la fenêtre sur une nouvelle ligne).
Le 3e paramètre peut être 'warn', 'help' ou 'error' (=> affichage d'une icône dans la fenêtre), ou être ignoré ou valoir 'none' (=> pas d'icône).

Un 4e paramètre mode peut être passé sous MATLAB (pas encore disponible sous Octave). Il peut avoir pour valeur :

  • 'non-modal' (effet identique au fait d'omettre de ce paramètre) : La fenêtre s'affiche de façon "non modale", c'est à dire que l'exécution du programme se poursuit après l'affichage de celle-ci
  • 'modal' : L'exécution du programme est suspendue jusqu'à ce que l'utilisateur clique sur le bouton OK
    On peut parvenir au même résultat sous Octave en faisant uiwait(msgbox(...))
Fenêtre d'avertissement :

msg={'Message d''avertissement', 'sur plusieurs lignes'};
warndlg(msg, 'Titre fenetre'); 

Cette fonction fournit le même résultat que msgbox(msg, titre, 'warn')

Sous MATLAB on peut passer à warndlg un 3e paramètre mode (voir remarque à ce sujet concernant msgbox)

Fenêtre d'aide :

msg={'Message d''aide', 'sur plusieurs lignes'};
helpdlg(msg, 'Titre fenetre'); 

Cette fonction fournit le même résultat que msgbox(msg, titre, 'help')

Sous MATLAB on peut passer à helpdlg un 3e paramètre mode (voir remarque à ce sujet concernant msgbox)

Fenêtre d'erreur :

msg={'Message d''erreur', 'sur plusieurs lignes'};
errordlg(msg, 'Titre fenetre'); 

Cette fonction fournit le même résultat que msgbox(msg, titre, 'error')

Sous MATLAB on peut passer à errordlg un 3e paramètre mode (voir remarque à ce sujet concernant msgbox)

Fenêtre de question oui/non :

Cette fonction suspend l'exécution du programme et affiche une fenêtre de question. L'exécution se poursuit lorsque l'on a cliqué sur l'un des 3 boutons.

msg={'Question sur', 'plusieurs lignes'};
bouton = questdlg(msg, 'Titre fenetre','Yes') 

Avec la première forme ci-dessus, affiche en-dessous du message msg les 3 boutons Cancel, No et Yes. Le 3e paramètres (facultatif, 'Yes' dans l'exemple ci-dessus) indique quel bouton est pré-sélectionné et sera activé si l'on presse enter. Retourne sur bouton la chaîne de caractère correspondant au nom du bouton pressé.
Différence de comportement entre MATLAB et Octave si on utilise la case de fermeture de la fenêtre au lieu des boutons : MATLAB retourne une chaîne vide, Octave retourne 'Cancel'

bouton = questdlg(msg, 'Titre fenetre', ...
                'Annuler', 'Non', 'Oui', 'Annuler') 
Avec la seconde forme ci-dessus, on spécifie le nom des boutons. Il peut y en avoir 2 ou 3 (ici 3), et on doit obligatoirement indiquer une chaîne supplémentaire spécifiant le nom du bouton activé par défaut si l'on presse enter.

Fenêtre de saisie de champs de texte :

Cette fonction suspend l'exécution du programme et affiche une fenêtre de saisie multi-champs. L'exécution se poursuit lorsque l'on a cliqué sur l'un des 2 boutons.

labels  = {'Prenom', 'Nom', 'Pays', 'Commentaire'};
li_cols = [1, 15; 1, 15; 1, 12; 2, 20];
val_def = {'', '', 'Suisse', ''};

vec_cel = inputdlg(labels, 'Titre fenetre', li_cols, val_def)

Affiche les champs de saisie étiquetés par les chaînes du vecteur cellulaire labels.

Le paramètre li_cols (facultatif, mais nécessaire si on veut passer le paramètre val_def) permet de définir la taille des champs :
• scalaire : nombre de lignes de tous les champs
vecteur à 2 éléments [lignes, colonnes] : nombre de lignes et de colonnes de tous les champs
• vecteur (avec autant d'éléments que labels) : nombre de lignes de chaque champ
• matrice (de 2 colonnes et autant de lignes que d'éléments dans labels) : nombre de lignes et de colonnes de chaque champ
Notez que sous MATLAB le paramètre colonnes affecte non seulement la largeur du champ mais aussi la largeur d'affichage des étiquettes labels !

Le vecteur cellulaire de chaînes val_def (paramètre facultatif) permet de pré-remplir les champs par des valeurs par défaut (ici le Pays Suisse).

Lorsque l'on clique Ok, la fonction retourne les données saisies dans les différents champs sur un vecteur cellulaire de chaînes vec_cel.

Fenêtre de sélection dans une liste :

Cette fonction suspend l'exécution du programme et affiche une fenêtre de sélection. L'exécution se poursuit lorsque l'on a cliqué sur l'un des 2 boutons inférieurs.

valeurs={'pommes','poires','cerises','kiwis','oranges'};
    
[sel_ind, ok] = listdlg('ListString', valeurs, ...
        'Name', 'Vos fruits', ...
        'PromptString', 'Fruits preferes :', ...
        'SelectionMode', 'Multiple', ...
        'ListSize', [100 140], ...
        'InitialValue', [1, 3], ...
        'OKString', 'J''ai choisi', ...
        'CancelString', 'Annuler');
if ok
  fprintf('Fruits choisis: ')
  for ind = 1:numel(sel_ind)
    fprintf([valeurs{sel_ind(ind)} ' '])
  end
  fprintf('\n')
end

Les paramètres d'entrée de listdlg sont définis par paire : 'mot-clé', valeur

Paramètre d'entrée obligatoire :
'ListString' réfère le vecteur cellulaire valeurs des éléments à afficher dans la liste

Paramètres d'entrée facultatifs :
'Name' définit le titre de la fenêtre
'PromptString' définit l'invite affichés au haut de la liste
'SelectionMode' peut être 'Multiple' (sélection possible de plusieurs valeurs avec ctrl-clic, mode par défaut) ou 'Single'
'ListSize' définit en pixels la taille [dx dy] de la zone d'affichage des valeurs
'InitialValue' réfère un vecteur contenant les indices dans valeurs des éléments qui seront présélectionnés ;
    en l'absence de ce paramètre ou si on spécifie [] :
    sous Octave : aucun élément n'est présélectionné
    sous MATLAB : le premier élément est présélectionné ( un bug dans le cas où l'on définit explicitement [])
'OKString' permet de redéfinir le texte du bouton Ok
'CancelString' permet de redéfinir le texte du bouton Cancel

Paramètres de sortie :
sel_ind est un vecteur ligne contenant les indices des éléments de valeurs que l'on a sélectionnés
ok retourne 1 si on a cliqué Ok, et 0 si on a cliqué Cancel




Menu de choix :

choix = menu('Titre', 'element1','element2',...) ou

v_cel = {'element1','element2',...} puis choix = menu('Titre', v_cel)

Implémente un menu retournant dans choix le numéro d'ordre de l'élément sélectionné :

  • MATLAB : ce menu apparaît sous forme d'une fenêtre dans laquelle chaque élement fait l'objet d'un bouton (voir figure de gauche ci-contre). Il suffit de cliquer sur un bouton pour refermer la fenêtre et continuer l'exécution du programme.

  • Octave : Sous Octave ≥ 4.0, ce menu est implémenté par une fenêtre analogue à celle de la fonction listdlg (voir figure de droite ci-contre). Le bouton Select All est désactivé. Il faut sélectionner l'élément désiré puis cliquer sur Ok pour refermer la fenêtre et continuer l'exécution du programme.

Si vous souhaitez implémenter un choix permettant de sélectionner plusieurs éléments, utilisez la fonction listdlg présentée plus haut.

Barre de progression :

handle = waitbar(fraction {,'texte'} )

Affiche une barre de progression ("thermomètre") de longueur définie par le paramètre fraction dont la valeur doit être comprise entre 0.0 (barre vide) et 1.0 (barre pleine). On utilise par exemple cette fonction pour faire patienter l'utilisateur en lui indiquant la progression d'un traitement d'une certaine durée.
Cette barre se présente sous la forme d'une fenêtre graphique que l'on pourra refermer avec close(handle). Attention, seul le 1er appel à waitbar peut contenir le paramètre texte (qui s'affichera au-dessus de la barre), sinon autant de fenêtre seront crées que d'appels à cette fonction !

barre = waitbar(0,'Patientez...');
for k=1:50
   pause(0.1)
     % pour les besoins de l'exemple, on
     %    fait ici une pause en lieu et
     %    place d'autres instructions...
   waitbar(k/50)
end
close(barre) 

8.1.3 Autres widgets

Fenêtre de sélection de fonte/style/taille :

a) structure = uisetfont();
b) uisetfont(h {, 'Titre'});

a) Affiche une fenêtre modale de sélection de police de caractères. Une fois que l'utilisateur a fait sa sélection, retourne sur la variable structure ce qui a été choisi, avec les champs FontName (nom de la police), FontWeight ('normal' ou 'bold'), FontAngle ('normal' ou 'italic'), FontUnits ('points'), FontSize (taille)

b) Permet de modifier interactivement la fonte/style/taille de l'objet (de type: text, axes, uicontrol) spécifié par son handle h. On peut optionnellement changer le Titre de cette fenêtre de dialogue.

8.1.4 Fenêtres de dialogue propres à Octave et basées sur Zenity

Bien que Octave implémente les fenêtres de dialogue standards vues plus haut, il supporte encore un autre jeu de widgets s'appuyant sur l'outil GNU/Linux Zenity. Voyez la page spécifique de notre support de cours.

8.2 Programmation GUI

Notez que sous Octave GUI la plupart des fonctionnalités décrites ci-après font leur apparition avec la version 4 et ne sont pleinement implémentées que sous le backend Qt.

8.2.1 Notions de base

Les interfaces-utilisateur graphiques (GUI) sous MATLAB/Octave sont élaborées dans des fenêtres de figure/graphiques. On y place des éléments d'interface appelés contrôles graphiques (UI controls) à l'aide de fonctions ui.... À ces éléments sont associés des fonctions de callback, définies par l'utilisateur, qui sont déclenchées lorsque l'utilisateur active ces éléments (p.ex. clic sur un bouton, choix dans un menu...), ces actions étant appelées des événements. L'élaboration d'interfaces graphiques fait ainsi appel à la programmation événementielle qui s'oppose à la programmation séquentielle.

Positionnement et dimension des fenêtres et éléments graphiques

En matière de GUI, on distingue sous MATLAB/Octave les deux systèmes d'axes suivants :
  • X/Y écran : système dont l'origine se situe à l'angle inférieur gauche de l'écran et dont les unités sont en pixels (points écran)

  • X/Y fenêtre : système dont l'origine se situe à l'angle inférieur gauche de la fenêtre ;
    différentes unités sont possibles (voir plus bas la propriété 'units' de la fonction uicontrol), les plus fréquemment utilisées étant :
    • pixels (unité par défaut pour les uicontrol notamment)
    • "unités normalisées" (unité par défaut pour annotation) : c'est un système d'unité indépendant de la taille de la fenêtre pour lequel l'angle inférieur gauche est (0,0) et l'angle supérieur droite est aux coordonnées fenêtre (1,1)
Pour définir la taille d'une fenêtre et la positionner sur l'écran, on doit spécifier les coordonnées-écran (xf,yf) de son angle inférieur gauche, sa largeur dxf et sa hauteur dyf.

De même, pour positionner un contrôle graphique, on doit spécifier les coordonnées-fenêtre (x1,y1) de son angle inférieur gauche, et sa largeur dx et hauteur dy, ou les coordonnées (x2,y2) de son angle supérieur droite.

Fenêtres GUI

dlg = figure('name','Titre', 'menubar','none', 'numbertitle','off' {, 'property', value ...} );
    dlg = dialog('name','Titre', 'windowstyle','normal' {, 'property', value ...} );

Fait apparaître une fenêtre de dialogue vide avec le Titre spécifié, et retourne son handle dlg. Ces deux fonctions produisent le même résultat !

Parmi les autres propriétés importantes dans l'initialisation de fenêtres de dialogue, mentionnons :

Une méthode alternative pour définir la position et dimension de la fenêtre est d'utiliser la commande : movegui({dlg,} position) où :
● si dlg n'est pas spécifié, la commande agit sur la fenêtre courante
position peut prendre la forme suivante :

a) uiwait(dlg {,timeout})
b) uiresume(dlg)

a) Suspend l'exécution du programme tant que la fenêtre dlg n'est pas fermée ou que uiresume n'est pas appelé. Le programme est alors en attente d'événements (boucle d'événements) qu'il traitera avec les callbacks définis.
En spécifiant un timeout (en secondes), la suspension ne dure que le laps de temps spécifié.

b) Reprend l'exécution du programme qui a été suspendu avec uiwait. Cette fonction est en principe invoquée depuis un callback.
Voir aussi la fonction waitfor(control, 'property') qui reprend l'exécution du programme lorsque la propriété proprety de l'élément control est modifiée par l'utilisateur via un callback.

{wait =} waitforbuttonpress

Suspend l'exécution du programme, et reprend celle-ci lorsque l'on clique dans la figure (retournant alors la valeur 0 sur wait) ou que l'on frappe une touche au clavier (retournant 1 sur wait).

Callbacks

Invocation d'un callback par un contrôle graphique ui_control (cela est aussi possible avec une fonction de dessin) :

a) ui_control(... , 'callback', 'code MATLAB/Octave' )
b) ui_control(... , 'callback', @fonction )
c) ui_control(... , 'callback', {@fonction, arg1, arg2 ...} )

a) Le callback est ici constitué par le code MATLAB/Octave défini sous forme de chaîne.

    Ex: uicontrol('string','Fermer', 'position',[200 300 100 25], 'callback','close; disp(''bye'')');
    Cette fonction crée un bouton (le 'style' par défaut étant 'pushbutton') nommé Fermer qui,
    lorsqu'on clique dessus, referme la fenêtre (par un close) et affiche "bye" dans la console MATLAB/Octave.

b) Le callback est ici une fonction utilisateur, appelée sans paramètre.

c) Le callback appelle ici la fonction spécifiée en lui passant des paramètres arg1, arg2....
    Noter que les accolades définissent ici bien un tableau cellulaire !
    Ex: voir ci-dessous l'appel à la fonction trigo

Notez que dans certaines fonctions ui... la propriété peut être dénommée 'clickedcallback', 'oncallback' ou 'offcallback'.

Écriture d'une fonction de callback :

function fonction(hsrc, event {, arg1, arg2 ...})
    code de la fonction ...
end
La fonction de callback doit spécifier au minimum les 2 premiers paramètres d'entrée hsrc et event :


Exemple Dans l'exemple ci-dessous illustré par la figure ci-contre, on affiche 2 champs et un popup-menu : dans le premier champ on peut introduire un angle en degrés, puis à l'aide du menu on choisit une fonction trigonométrique qui affiche, dans le second champ, le sinus ou le cosinus de l'angle.

On peut quitter l'application avec le bouton Quitter ou avec le menu Fichier > Quitter.

En surveillant les frappes clavier effectuées dans la fenêtre (hormis dans les champs de saisie), on définit en outre que enter a le même effet que le bouton Quitter (technique utilisée pour définir un bouton par défaut).

function exemple_callback
  dlg = figure('name','Exemple de callbacks', 'position',[200 500 320 100], ...
               'menubar','none', 'numbertitle','off', 'KeyPressFcn',@clavier);
  m1 = uimenu(dlg, 'label','&Fichier', 'accelerator','f');                     % menu avec raccourci alt-f
  uimenu(m1, 'label','Quitter', 'accelerator', 'q', 'callback','close');       % article avec raccourci ctrl-q
  champ1 = uicontrol(dlg, 'style','edit', 'string','0', 'position',[30 60 50 25]);
  champ2 = uicontrol(dlg, 'style','edit', 'position',[200 60 90 25]);
  uicontrol(dlg, 'style','popupmenu', 'string',{'sin','cos'}, 'position',[100 60 50 25], ...
            'callback', {@trigo, champ1, champ2});
  uicontrol(dlg, 'style','pushbutton', 'string','Quitter', 'position',[120 10 80 25], 'callback','close');
end


function trigo(h,e, ch1, ch2)
  angle = deg2rad(str2num(get(ch1,'string')));  % récupère angle (degrés) dans 1er champ et conversion (radians)
  menu  = get(h,'string');         % récupère articles du menu popup {'sin', 'cos'}
  fct = menu{get(h,'value')};      % récupère l'article sélectionné
  switch fct
    case 'sin'
      res = sin(angle);
    case 'cos'
      res = cos(angle);
  end
  set(ch2,'string', num2str(res))  % affiche le sinus ou cosinus de l'angle dans 2e champ
end


function clavier(h,e)
  fprintf('La touche ''%s'' a ete pressee !\n', e.Key)
  if strcmp(e.Key, 'return')
    close
  end
end

8.2.2 Éléments d'interface graphique (UI Controls)

Menus

Fonction et description
Exemple Illustration
hm = uimenu({dlg,} 'label','texte' {, 'accelerator','car'} {, 'property',value ...} );
Ajoute, dans la fenêtre dlg (ou la fenêtre courante si dlg n'est pas spécifié), le menu avec le libellé texte indiqué. On pourra déplier ce menu avec la souris ou le raccourci clavier alt-car.
Inséré à l'intérieur du texte du menu, le caractère & désigne à sa droite le caractère qui sera souligné lorsque l'on frappe alt. Cela permet de mettre en évidence les raccourcis des entrées principales des menus.
uimenu(hm, 'label','article' {, 'accelerator','car'} , 'callback',callback {, 'property',value ...} )
Ajoute l'article de menu spécifié dans le menu hm. Le choix de cet article par l'utilisateur ou l'usage du raccourci clavier ctrl-car activera le callback.
Parmi les propriétés intéressantes, mentionnons :
  • 'enable','off|on' : désactive (grise) ou réactive l'article de menu
  • 'separator','on|off' : ajoute ou enlève une ligne de séparation au-dessus de l'article
  • 'checked','on|off' : ajoute ou enlève le caractère "vu" à gauche de l'article
Ex Menu utilisateur (illustré ci-contre avec Octave sous Ubuntu/Unity)
m1 = uimenu('label','&Fichier', 'accelerator','f'); % => alt-f
uimenu(m1, 'label','Quitter', 'accelerator','q', ...
        'callback','close');  % => ctrl-q
Dans la première figure, notez bien le "F" qui apparaît en souligné. Et dans la seconde figure, la mention du raccourci "Ctrl-Q".
alt affiche :  

alt-f affiche :  

a) hcm = uicontextmenu({dlg,});
b) uimenu(hcm, 'label','article1', 'callback',callback1)
    uimenu(hcm, 'label','article2', 'callback',callback2)
c) set(dlg, 'uicontextmenu', hcm);
a) et c) Met en place un menu contextuel dans la fenêtre dlg (ou la fenêtre courante), c'est-à-dire le menu apparaissant avec clic-droite
b) Ajoute l'article spécifié dans ce menu. Le choix de celui-ci par l'utilisateur activera le callback.
Ex Menu contextuel (illustré ci-contre avec Octave sous Ubuntu/Unity)

Ce menu contextuel change la colormap de la fenêtre de figure :

dlg = dialog('name','Titre', 'windowstyle','normal');
cm = uicontextmenu(dlg);
uimenu(cm, 'label','Hot',    'callback','colormap(hot)')
uimenu(cm, 'label','Winter', 'callback','colormap(winter)')
set(dlg, 'uicontextmenu',cm);
clic-droite affiche :  

Barres d'outils

Les toolbars sont des barres d'outils qui prennent place au haut de la fenêtre, en-dessous de la barre de menus.

Fonction et description
Exemple Illustration
a) dlg = figure('toolbar','none')
b) htb = uitoolbar(dlg)
a) Suppression de toutes les éventuelles toolbars existantes de la fenêtre dlg.
b) Mise en place d'une nouvelle toolbar vide dans la fenêtre dlg. Le cas échéant elle prend place en-dessous des toolbars existantes.

Avec set(htb, 'visible','off|on'), on peut après coup masquer ou faire réapparaître cette toolbar.

hb = uipushtool(htb, 'cdata',icon {, 'tooltipstring','texte'}, 'clickedcallback',callback);
Insère un bouton dans la toolbar htb, le cas échéant à la suite (à droite) des boutons existants. Survoler le bouton avec la souris fait apparaître le "tooltip" texte. Cliquer sur le bouton activera le callback.

L'apparence du bouton est définie par un tableau 3D icon de dimension hauteur x largeur x 3 représentant une image de hauteur x largeur pixels par leurs 3 composantes RGB. Noter que largeur et hauteur semblent ne pas devoir dépasser 16 pixels. Si l'on désire utiliser une image provenant d'un fichier, il faudra la lire avec imread, puis la convertir en fichier-image RGB avec ind2rgb, puis éventuellement la resizer avec imresize[O: image].

Avec 'separator','on' on peut ajouter à gauche du bouton un séparateur vertical.
Avec set(hb, 'visible','off|on') on peut après coup masquer ou faire réapparaître le bouton hb.

ht = uitoggletool(htb, 'cdata',icon, 'clickedcallback',cback_clic, 'oncallback',cback_on, 'offcallback',cback_off);
Insère dans la toolbar htb (le cas échéant à droite des boutons existants) un bouton à bascule, c'est-à-dire qui passe à chaque clic de l'état relâché (off) à l'état pressé (on) et vice versa. Chaque clic par l'utilisateur active le callback cback_clic. En plus lorsque le bouton passe à l'état pressé le callback cback_on est activé, et lorsqu'il est relâché c'est le callback cback_off qui est activé.

Mêmes remarques que pour uipushtool concernant l'icon, et l'on peut aussi utiliser les propriétés 'tooltipstring' et 'visible'.



Exemple Dans l'exemple ci-dessous illustré par la figure ci-contre, on met en place une barre d'outils se composant de 2 boutons simples (noir et rouge) et d'un bouton à bascule (vert/cyan). Remarquez le "tooltip" (ici "Noir") qui apparaît quand on survole le bouton avec la souris, ainsi que le séparateur que l'on a mis en place entre le 2e et le 3e bouton. Vous constaterez aussi, si vous exécutez ce code, que l'on a programmé un changement d'icône du bouton à bascule selon qu'il est relâché (vert) ou enfoncé (cyan). Pour illustrer le callback de ces boutons, on affiche les événements dans la console MATLAB/Octave.

function exemple_toolbar
  dlg = figure('toolbar','none', 'name','Exemple de toolbar', 'numbertitle','off');
  
  icon1          =zeros(16,16,3);  # carré noir
  icon2(:,:,1)   =ones(16,16);  icon2(:,:,2)   =zeros(16,16);  icon2(:,:,3)   =zeros(16,16); # carré rouge
  icon_off(:,:,1)=zeros(16,16); icon_off(:,:,2)=ones(16,16)/2; icon_off(:,:,3)=zeros(16,16); # carré vert
  icon_on(:,:,1) =zeros(16,16); icon_on(:,:,2) =ones(16,16);   icon_on(:,:,3) =ones(16,16);  # carré cyan
  
  ht = uitoolbar(dlg);
  uipushtool(ht,  'cdata',icon1,    'tooltipstring','Noir',   'clickedcallback','disp(''noir'')');
  uipushtool(ht,  'cdata',icon2,    'tooltipstring','Rouge',  'clickedcallback','disp(''rouge'')');
  uitoggletool(ht,'cdata',icon_off, 'tooltipstring','Toggle', 'clickedcallback','disp(''clic'')', ...
              'oncallback',{@toggle, icon_on}, 'offcallback',{@toggle, icon_off}, 'separator','on');
end
    
function toggle(h,e, icon)
  disp(get(h,'state'))
  set(h, 'cdata',icon)
end

Contrôles graphiques (boutons, champs, menus déroulants, checkboxes, boutons radio, curseurs...)

Fonction et description
Exemple Illustration
hc = uicontrol({dlg|hp,} 'style','style', 'position',position {, 'units','unites'} {, 'callback',callback} {'property',value ...} );
Le contrôle graphique spécifié par son style est inséré dans la fenêtre courante, ou dans celle spécifiée par dlg, ou dans le "panel" hp spécifié.
Il est placé à la position spécifiée définie par défaut en pixels. Il est possible de travailler dans d'autres unités en spécifiant : 'units', 'normalized | pixels | points | characters | centimeters | inches'. Les "unités normalisées" (voir plus haut) sont intéressantes en ce sens qu'elles sont indépendantes de la taille de la fenêtre.
Si l'on omet de définir un style, c'est un contrôle graphique de type pushbutton qui est dessiné.

Parmi les properties communes à tous les contrôles graphiques, citons :
- 'tooltipstring','texte' : affiche le texte spécifié quand le curseur survole le contrôle graphique
- 'visible','off|on' : masque ou rend visible le contrôle graphique
- 'enable','off|on' : désactive le contrôle graphique (qui est alors grisé) ou le réactive
- 'string','texte', 'fontsize',taille : texte associé au contrôle graphique et sa taille (par défaut en "points")
  'foregroundcolor',couleur : couleur du texte du contrôle graphique
- 'backgroundcolor',couleur : couleur de fond du contrôle graphique
Les properties spécifiques à chaque style sont précisées ci-dessous.

On distingue les contrôles graphiques suivants selon la valeur de l'attribut style :

'style','pushbutton', 'string','texte', 'position',[x1 y1 dx dy]ex 1
Affiche un bouton texte à l'emplacement x1 y1 et de taille dx dy.
Pour définir une action qui serait exécutée lorsqu'on frappe une touche clavier, typiquement un "bouton par défaut" invoqué par la touche enter, définir un callback 'KeyPressFcn' global pour la fenêtre GUI (figure ou dialog). Cela est illustré par l' ex "exemple_callback" plus haut.
'style','togglebutton', 'string','texte', 'position',[x1 y1 dx dy], 'value','0|1'ex 2
Affiche un bouton à bascule texte qui passe à chaque clic de l'état enfoncé ("On", où la propriété 'value' est à 1) à l'état relâché ("Off", où celle-ci est à 0) et vice versa.
'style','text', 'string','texte', 'position',[x1 y1 dx dy], ...
    'horizontalalignment','center|left|right', 'verticalalignment','middle|top|bottom'ex 3
Affiche le texte spécifié à la position x1 y1, positionné par défaut de façon centrée sur la largeur dx et la hauteur dy.
Voir par ailleurs les propriétés 'fontsize', 'foregroundcolor', 'backgroundcolor' ci-dessus.
'style','edit', {'string','texte',}, 'position',[x1 y1 dx dy], 'horizontalalignment','center|left|right' ex 3
Affiche un champ de saisie de texte à l'emplacement x1 y1 et de taille dx dy. Le contenu initial peut être défini avec la propriété 'string'
'style','popupmenu', 'string',cell_text, 'position',[x1 y1 dx dy]ex 4
Affiche un menu déroulant à l'emplacement x1 y1 et de taille dx dy. Le libellé des articles du menu est défini par un tableau cellulaire de chaînes cell_text. Avec le callback, on récupère sur la propriété 'value' le numéro de l'article de menu qui a été choisi par l'utilisateur.
'style','listbox', 'string',cell_text, 'max',max, 'position',[x1 y1 dx dy]ex 5
Affiche une boîte de sélection dans une liste. Analogue au popupmenu ci-dessus, sauf que la liste est ici dépliée et que l'on peut faire une sélection multiple (discontinue par ctrl-clic, ou continue par maj-clic) si max est supérieur à 1. Avec le callback, on récupère sur la propriété 'value' un vecteur contenant les numéros des éléments qui ont été sélectionnés par l'utilisateur.
'style','checkbox', 'string','texte', 'value','0|1', 'position',[x1 y1 dx dy]ex 6
Affiche une boîte à cocher suivie du texte spécifié, à l'emplacement x1 y1 et dans un espace de taille dx dy. L'état initial de la boîte est défini par la propriété 'value' : décochée avec 0, et cochée avec 1.
'style','radiobutton', 'string','texte', 'value','0|1', 'position',[x1 y1 dx dy]ex 8
Affiche un bouton radio. Pour le reste, strictement identique à la checkbox ci-dessus. Pour faire en sorte que, dans un groupe de boutons radio, le clic de l'un désactive les autres, voir la fonction uibuttongroup plus bas.
'style','slider', 'min',vmin, 'max',vmax, 'value',val, 'position',[x1 y1 dx dy]ex 7
Affiche un curseur à l'emplacement x1 y1 et de taille dx dy. La position de gauche du bouton du curseur correspond à la valeur vmin, celle de droite à la valeur vmax. La position initiale du bouton est définie par val, et c'est donc sur la propriété 'value' que le callback récupère la position choisie par l'utilisateur.
'style','frame'
Analogue aux fonctions uipanel ou uibuttongroup présentées ci-dessous et qu'il est préférable d'utiliser → ex 9
Ex 1 Boutons (illustré ci-contre avec Octave sous Ubuntu/Unity)
uicontrol('style','pushbutton', 'string','Oui', ...
    'position',[10  10  50 30], 'callback','disp(''oui'')');
uicontrol('style','pushbutton', 'string','Non', ...
    'position',[70  10  50 30], 'callback','disp(''non'')');
uicontrol('style','pushbutton', 'string','Quitter', ...
    'position',[150 10 100 30], 'callback','close', ...
    'tooltipstring','Fermer la fenetre');

Remarquez le tooltip associé au bouton Quitter

Ex 2 Bouton à bascule (illustré ci-contre avec Octave sous Ubuntu/Unity)
function test_togglebutton
  dialog('name','Togglebutton', 'windowstyle','normal')
  uicontrol('style','togglebutton', 'string','Off', ...
    'position',[10 380 100 30], 'value',0, ...
    'callback',@cbk_togglebutton);
end

function cbk_togglebutton(h,e)
  if get(h,'value')   % égal à 1 => true
    set(h,'string','On');  disp('on');
  else
    set(h,'string','Off'); disp('off');
  end
end

Dans cet exemple, on change le libellé du bouton selon qu'il est enfoncé (On) ou relâché (Off)

Ex 3 Texte et champ de saisie (illustré ci-contre avec Octave sous Ubuntu/Unity)
uicontrol('style','text', 'string','Nom / prenom', ...
    'position',[10 380 100 30], ...
    'foregroundcolor', 'b', 'backgroundcolor','w', ...
    'fontangle','italic', 'horizontalalignment','left');

uicontrol('style','edit', 'string','...', ...
    'position',[120 380 180 30], 'horizontalalignment','left');
Ex 4 Menu déroulant (illustré ci-contre avec Octave sous Ubuntu/Unity)
function test_popupmenu
  liste={'Suisse','France','Italie','Allemagne','Espagne', ...
    'Belgique','Luxembourg','Portugal'};
  uicontrol('style','popupmenu', 'string',liste, ...
    'position',[10 380 100 30], 'callback', @cbk_popupmenu);
end

function cbk_popupmenu(h,e)
  menu_itemms = get(h,'string');
  disp(menu_itemms{get(h,'value')})
end

Menu replié...   et déplié

Ex 5 Boîte de sélection dans une liste (illustré ci-contre avec Octave sous Ubuntu/Unity)
function test_listbox
  liste={'Suisse','France','Italie','Allemagne','Espagne', ...
    'Belgique','Luxembourg','Portugal'};
  uicontrol('style', 'listbox', 'string',liste, 'max',2, ...
    'position',[10 250 100 160], 'callback', @cbk_listbox);
end

function cbk_listbox(h,e)
  disp(get(h,'value'))
end
Dans cet exemple on rend possible la sélection multiple avec 'max',2
Ex 6 Boîtes à cocher (illustré ci-contre avec Octave sous Ubuntu/Unity)
function test_checkbox
  for k=1:5; 
    hcb(k)=uicontrol('style','checkbox', ...
    'string',['Article ' num2str(k)], 'value',0, ...
    'position',[10 400-20*k 100 20], 'callback',{@cbk_checkbox k});
  end
  uicontrol('style','pushbutton', 'string','Commander', ...
    'position',[10 260 100 30], 'callback',{@cbk_commande hcb});
end

function cbk_checkbox(h,e, k)
  if get(h,'value')
    status = 'on';
  else
    status = 'off';
  end
  fprintf(' article %d %s \n', k, status)
end

function cbk_commande(h,e, hcb)
  fprintf('commande articles: ')
  for k=1:5
    if get(hcb(k),'value')  % égal à 1 => true
      fprintf('%s ',num2str(k))
    end
  end
  fprintf('\n')
end

Dans cet exemple, chaque clic active le callback "cbk_checkbox". De plus le bouton Commander active le callback "cbk_commande" qui relève l'état de toutes les boîtes à cocher.

Ex 7 Curseur (illustré ci-contre avec Octave sous Ubuntu/Unity)
function test_slider
  uicontrol('style','text', 'string','Température', ...
    'position',[10 370 100 30]);
  uicontrol('style','slider', 'position', [130 375 250 15], ...
    'min',-10, 'max',30, 'value',0, ...
    'callback', @cbk_slider); 
end

function cbk_slider(h,e)
  disp(get(h,'value'))
end
hbg = uibuttongroup('title','texte', 'position',[x1 y1 dx dy]);

Crée un "panel" spécifique permettant de grouper et lier des boutons radios, c'est-à-dire faire en sorte que le clic de l'un désactive automatiquement les autres. Ce panel est placé en x1 y1 et a une taille dx dy, mais il faut noter que ces valeurs sont définies par défaut en "unités normalisées" (comme pour uipanel) et non pas en pixels (comme pour uicontrol) ! Un cadre est automatiquement dessiné autour de ce panel avec le titre title.

Ex 8 Groupe de boutons radio (illustré ci-contre avec Octave sous Ubuntu/Unity)
function test_uibuttongroup
  hbg = uibuttongroup('title','Sexe', ...
    'position',[.05 .65 .25 .3]);  % unités normalisées !!!
  uicontrol(hbg, 'style','radiobutton', 'string','Femme', ...
    'value',0, 'position',[10 80 100 20], 'callback',{@cbk_radio 'femme'});
  uicontrol(hbg, 'style','radiobutton', 'string','Homme', ...
    'value',0, 'position',[10 50 100 20], 'callback',{@cbk_radio 'homme'});
  uicontrol(hbg, 'style','radiobutton', 'string','N/A', ...
    'value',1, 'position',[10 20 100 20], 'callback',{@cbk_radio 'n/a'});
end

function cbk_radio(h,e, sexe)
  if get(h,'value')
    disp(sexe)
  end
end

Notez que le choix initial du bouton pressé est défini par celui qui a la propriété 'value',1, donc ici "N/A". Notez aussi que les 3 boutons étant liés (exclusifs), le clic sur l'un génère exactement 2 appels au callback : pour le passage à On de celui que l'on clique, et pour le passage automatique à Off de celui qui était à On.

hp = uipanel('title','texte', 'position',[x1 y1 dx dy], ...
    'fontsize',taille, 'foregroundcolor',coul1, 'backgroundcolor',coul2)

Dessine un "panel" en x1 y1 et de taille dx dy, ces valeurs étant par défaut exprimées en "unités normalisées" et non pas en pixels (comme pour uicontrol) ! Un cadre est dessiné autour de ce panel avec le titre texte dans la taille spécifiée. On peut optionnellement spécifier les couleurs coul1 du texte et coul2 du fond.

Un "panel" n'est donc rien d'autre qu'un élément décoratif de GUI permettant de regrouper esthétiquement les contrôles graphiques. On peut imbriquer des panels les uns dans les autres de façon hiérarchiquee.

uicontrol('parent',hp, 'style','style', 'position',[x1 y1 dx dy] ...)   ou plus simplement :
uicontrol(hp,          'style','style', 'position',[x1 y1 dx dy] ...)

Place un contrôle graphique dans un (sous-)panel.
Attention : il faut noter que dans ce cas les coordonnées x1 y1 se réfèrent à l'angle inférieur gauche du panel et non pas de la figure !

Ex 9 Panels imbriqués (illustré ci-contre avec Octave sous Ubuntu/Unity)
dialog('name','Exemple de uipanel', 'windowstyle','normal')

hp  = uipanel('title','Panel principal', 'position',[.1 .1 .8 .66], ...
    'fontsize',16, 'backgroundcolor','white');

hsp1= uipanel(hp,'title','Sous-panel 1', 'position',[.1 .1 .4 .4], ...
    'fontsize',12, 'backgroundcolor','y');  % sous-panel du panel hp
hsp2= uipanel(hp,'title','Sous-panel 2', 'position',[.6 .1 .3 .4], ...
    'fontsize',12, 'backgroundcolor','c');  % sous-panel du panel hp

uicontrol(hsp1,'string','Fermer', 'position',[15 15 80 30], ...
    'callback','close');   % bouton dans le sous-panel 1
uicontrol('style','text', 'string','Exemple uipanel', ...
    'units','normalized', 'position', [.1 .85 .8 .1], ...
  'foregroundcolor', 'w', 'backgroundcolor',[.4 .4 .4], ...
  'horizontalalignment','center', 'fontangle','italic', ...
  'fontsize',20);          % texte en-dehors des panels

Tableaux de données

Remarque : sous Octave, la fonction uitable fait son apparition avec la version 5.

Fonction et description
Exemple Illustration
htab = uitable({dlg,} 'Data', tableau {,'property',value ...} )

Affiche, dans la fenêtre dlg et sous forme de table, les données de tableau, et récupère le handle htab de cet objet.

La variable tableau doit être de type numérique ou cellulaire, et de dimension 1D (vecteur) ou 2D (matrice).
Si l'on omet dlg, le tableau est affiché dans la fenêtre de figure courante. Si aucune fenêtre de figure n'existe, une fenêtre est créée.

Parmi les properties disponibles, on peut mentionner :
- 'ColumnName', 'numbered'|vec_cel : en-têtes de colonnes numérotées incrémentalement (défaut), ou selon les données spécifiées dans vecteur cellulaire vec_cel
- 'RowName', 'numbered'|vec_cel : en-tête de lignes numérotées incrémentalement (défaut), ou selon les données spécifiées dans vecteur cellulaire vec_cel
- 'ColumnWidth', 'auto'|vec_cel : largeur des colonnes automatique (défaut), ou selon les données spécifiées dans vecteur cellulaire vec_cel en pixels
- 'ForegroundColor',couleur : couleur du texte, spécifiés sous forme de nom de couleur (tel que 'r') ou de triplet RGB (tel que [1 0 0]), par défaut noire
- 'BackgroundColor',mat2x3 : couleur de l'arrière plan des cellules en alternance lignes impaires (mat2x3(1,:)) et lignes paires (mat2x3(2,:)) ; par défaut [1 1 1;.94 .94 .94]
- 'Position',[x1 y1 dx dy] : en pixels : dimension (largeur dx, hauteur dy), et position de la table (x1 et y1) par rapport à angle inférieur gauche de la fenêtre

Faire get(htab) pour découvrir les autres propriétés disponibles, notamment celles permettant l'interaction avec le tableau.

Ex
personnes={
  'Jules','Dupond',24
  'Albertine','Durand',30
  'Robert','Muller',28
} ;
entete_col={'Prenom', 'Nom', 'Age'} ;
coul_alternee=[1  1  1 ; 1  1 .8] ;

dlg = figure('name','Utilisateurs', 'menubar','none', ...
  'numbertitle','off', 'position',[10 10 350 200]) ;
movegui(dlg,'west')

htab=uitable(dlg, 'Data',personnes, ...
  'ColumnName',entete_col, ...
  'ColumnWidth',{120 120 30}, ...
  'ForegroundColor','b', ...
  'BackgroundColor',coul_alternee, ...
  'Position',[20 20 300 150] ...
) ;

Annotations

Fonction et description
Exemple Illustration
a) annotation('line', [x1 x2], [y1 y2] {, 'property',value ...} )
b) annotation('arrow', [x1 x2], [y1 y2] ...)
c) annotation('doublearrow', [x1 x2], [y1 y2] ...)
d) annotation('textarrow', [x1 x2], [y1 y2] ...)

e) annotation('textbox', [x1 y1 dx dy] ...)
f) annotation('rectangle', [x1 y1 dx dy] ...)
g) annotation('ellipse', [x1 y1 dx dy] ...)

Habille une fenêtre de dialogue (ou figure) avec un élément graphique de type :
a) ligne
b) flèche
c) double flèche
d) texte associé à une flèche
e) boîte avec du texte
f) rectangle
g) ellipse

L'annotation est positionnée aux coordonnées figure x1 et y1. Elle s'étend jusqu'à x2 et y2, ou a la dimension dx et dy. Ces valeurs sont exprimées par défaut en "unités normalisées" (voir plus haut) et non pas en pixels. On peut changer d'unités avec la property 'units', 'pixels | normalized | points | characters | centimeters | inches'.
Attention : notez que si vous placez une annotation dans un graphique, celle-ci est fixe par rapport à la fenêtre et ne "bouge" donc pas si l'on fait un pan/zoom/rotation du graphique.

Ex Les différents types d'annotations (illustré ci-contre avec Octave sous Ubuntu/Unity)
dialog('name', 'Exemple d''annotations', ...
    'WindowStyle', 'normal') % dialogue non "modal"
% ou commande "figure"

annotation('line', [.5 .9], [.1 .6], 'color','b', ...
    'linewidth',4, 'linestyle',':')
annotation('arrow', [.2 .4], [.9 .6], 'color',[0 .5 0], ...
    'linewidth',3, 'linestyle','--')
annotation('doublearrow', [.35 .6], [.45 .45], ...
    'color','g', 'linewidth',3, 'linestyle','-')
annotation('textarrow', [.7 .6], [.8 .6], ...
    'string','annotation')
annotation('textbox', [.5 .5 0 0], 'string', 'Hello !', ...
    'fontsize',30, 'horizontalalignment','center', ...
    'color','r', 'edgecolor','none', 'backgroundcolor','none')
annotation('rectangle', [.15 .1 .25 .2],'facecolor',[1 1 0], ...
    'edgecolor',[.5 .5 0],'linewidth',6, 'linestyle','-')
annotation('ellipse', [.8 .1 .1 .3], ...
    'facecolor',[.8 .8 1],'edgecolor','none')

8.2.3 Un exemple complet d'application GUI

L'application présentée ci-dessous réalise ce qui suit :

Figure 1 Figure 2 Figure 3
Figure 4 Figure 5

function appli_gui      % Programme principal
  disp('Application graphique "modale" (à piloter depuis fenetre graphique)')

  global dlg
  dlg = figure('name','Application GUI (voir menus)', 'menubar','none', 'numbertitle','off');
  % ou: dlg = dialog('name', 'Application GUI (voir menus)', 'windowstyle','normal');
  
  screen_size = get(0,'screensize') ;               % taille de l'écran
  screen_center = screen_size(3:4)/2 ;              % coordonnées x/y du centre de l'écran
  dialog_size = [600 400] ;                         % taille de la fenetre d'application
  dialog_pos = screen_center - dialog_size/2 ;      % pour centrer fenetre sur l'écran
  set(dlg, 'position',[dialog_pos dialog_size], 'color',[.8 .8 .8])
  
  dialog_init
  uiwait(dlg);  % utile lorsque 'windowstyle' est à 'normal' pour que l'appli tourne de façon modale
end

% ***** Initialisation fenetre GUI (menus, boutons) ********************************************************************

function dialog_init
  global dlg
  clf(dlg)  % efface la fenetre (y compris menus ; sinon utiliser "cla(handle)")
  
  m1 = uimenu(dlg, 'label','&Fichier',    'accelerator','f');                               % =>  alt-f
  uimenu(m1, 'label','Quitter',           'accelerator','q', 'callback', @quitter);         % =>  ctrl-q

  m2 = uimenu(dlg, 'label','&Calculette', 'accelerator','c');                               % =>  alt-c
  uimenu(m2, 'label','Arithmetique',      'accelerator','a', 'callback', @calc_arith);      % =>  ctrl-a
  uimenu(m2, 'label','Trigonometrique',   'accelerator','t', 'callback', @calc_trigo);      % =>  ctrl-t

  m3 = uimenu(dlg, 'label','&Graphiques', 'accelerator','g');                               % =>  alt-g
  uimenu(m3, 'label','Sinus et Cosinus',  'accelerator','n', 'callback', @graph_sincos);    % =>  ctrl-n
  uimenu(m3, 'label','Surface 3D',        'accelerator','s', 'callback', @graph_3d);        % =>  ctrl-s
  
  m4 = uimenu(dlg, 'label','&Aide',       'accelerator','h');                               % =>  alt-a
  uimenu(m4, 'label','Infos',             'accelerator','i', 'callback', @infos);           % =>  ctrl-i
  
  uicontrol(dlg, 'style','pushbutton', 'string','Infos',   'units','normalized', 'position',[.05 .05 .15 .1], 'callback', @infos);
  uicontrol(dlg, 'style','pushbutton', 'string','Quitter', 'units','normalized', 'position',[.8  .05 .15 .1], 'callback', @quitter);
  
  global erreur
  erreur = uicontrol('style','text', 'visible','off', 'units','normalized', 'position',[.1 .25 .8 .06], ...
        'horizontalalignment','center', 'foregroundcolor','r', 'backgroundcolor',[1 .8 .8]);
  % ou: erreur = annotation(dlg, 'textbox', [.1 .25 .8 .06], 'visible','off', 'horizontalalignment','center', ...
  %     'color','r', 'backgroundcolor',[1 .8 .8], 'edgecolor','none', 'fitboxtotext','off');
end

% ***** Calculette Arithmétique ****************************************************************************************

function calc_arith(h,e)
  dialog_init
  ch1 = uicontrol('style','edit', 'string','0', 'units','normalized', 'position',[.2  .6 .2 .07]);
  ch2 = uicontrol('style','edit', 'string','0', 'units','normalized', 'position',[.6  .6 .2 .07]);
  uicontrol('style','text', 'string', '=>', 'units','normalized',     'position',[.25 .4 .1 .07], 'backgroundcolor',[.8 .8 .8]);
  ch3 = uicontrol('style','edit', 'units','normalized',               'position',[.35 .4 .3 .07]);
  uicontrol('style','pushbutton', 'string','+', 'units','normalized', 'position',[.46 .65 .07 .07], ...
        'callback', {@c_arith, '+', ch1, ch2, ch3});
  uicontrol('style','pushbutton', 'string','-', 'units','normalized', 'position',[.46 .55 .07 .07], ...
        'callback', {@c_arith, '-', ch1, ch2, ch3});
end


function c_arith(h,e, oper, ch1, ch2, ch3)
  nb1=str2num(get(ch1,'string'));
  nb2=str2num(get(ch2,'string'));
  
  global erreur  % handle vers la zone d'affichage d'erreur
  if isempty(nb1) && isempty(nb2)
    set(erreur, 'string', 'Erreur: les deux champs ne contiennent pas de nombres', 'visible','on')
    set(ch1, 'backgroundcolor','y'); set(ch2, 'backgroundcolor','y');
    
  elseif isempty(nb1)
    set(erreur, 'string', 'Erreur: le 1er champ ne contient pas un nombre', 'visible','on')
    set(ch1, 'backgroundcolor','y'); set(ch2, 'backgroundcolor','w');
    
  elseif isempty(nb2)
    set(erreur, 'string', 'Erreur: le 2e  champ ne contient pas un nombre', 'visible','on')
    set(ch1, 'backgroundcolor','w'); set(ch2, 'backgroundcolor','y')
    
  else
    set(erreur, 'visible','off')
    set(ch1, 'backgroundcolor','w'); set(ch2, 'backgroundcolor','w')
    switch oper
      case '+'
        set(ch3, 'string',num2str(nb1+nb2))
      case '-'
        set(ch3, 'string',num2str(nb1-nb2))
    end
  end
  
end

% ***** Calculette Trigonométrique *************************************************************************************

function calc_trigo(h,e)
  dialog_init
  champ1 = uicontrol('style','edit', 'string','0', 'units','normalized', 'position',[.25 .6 .15 .07]);
  uicontrol('style','text', 'string','degres =>',  'units','normalized', 'position',[.4  .6 .15 .07], 'backgroundcolor',[.8 .8 .8]);
  champ2 = uicontrol('style','edit', 'string',' ', 'units','normalized', 'position',[.6  .6 .30 .07]);
  uicontrol('style','popupmenu', 'string',{'sin','cos','tan'}, 'horizontalalignment','center', ...
        'units','normalized', 'position',[.1 .6 .12 .07], 'callback', {@c_trigo, champ1, champ2});
end


function c_trigo(h,e, ch1, ch2)
  angle = deg2rad(str2num(get(ch1,'string')));
  menu  = get(h,'string');
  choix = get(h,'value');
  switch (menu{choix})
    case 'sin'
      res=sin(angle);
    case 'cos'
      res=cos(angle);
   case 'tan'
      res=tan(angle);
  end
  set(ch2, 'string',num2str(res))
end

% ***** Graphique Sinus et Cosinus *************************************************************************************

function graph_sincos(h,e)
  dialog_init
  global dlg
  uicontrol(dlg, 'style','pushbutton', 'string','sinus',   'units','normalized', 'position',[.8 .52 .15 .1], ...
        'callback', {@g_sincos, 'sin'});
  uicontrol(dlg, 'style','pushbutton', 'string','cosinus', 'units','normalized', 'position',[.8 .40 .15 .1], ...
        'callback', {@g_sincos, 'cos'});
end


function g_sincos(h,e, fct)
  fplot(fct, [0 4*pi])
  title(fct,'fontsize',16)
  grid('on')
end

% ***** Graphique Surface 3D *******************************************************************************************

function graph_3d(h,e)
  dialog_init
  global dlg
  eclairage = 1 ;  elevation = 30 ;  orientation = 30 ;
  g3d(eclairage, orientation, elevation)
  uicontrol('style','text', 'string','Orientation', 'units','normalized', 'position',[.05 .87 .15 .1], 'backgroundcolor',[.8 .8 .8]);
  uicontrol(dlg, 'style','slider', 'min',0, 'max',90, 'value',orientation, 'units','normalized', 'position',[.20 .9 .25 .04], ...
        'callback', {@g3d_orient, elevation}); 
  uicontrol('style','text', 'string','Eclairage',   'units','normalized', 'position',[.5 .87 .15 .1],  'backgroundcolor',[.8 .8 .8]);
  uicontrol(dlg, 'style','slider', 'min',0, 'max',1, 'value',eclairage,   'units','normalized',  'position',[.65 .9 .25 .04], ...
        'callback', @g3d_eclair); 
end


function g3d(eclair, orient, elev)
  handle = surf(peaks(100));
  set(get(handle, 'parent'), 'position',[.2 .15 .6 .7])     % diminution taille zone graphique
  set(gca,'xticklabel',[],'yticklabel',[],'zticklabel',[])  % ou:  axis('nolabel')  sous Octave
  shading('interp')
  view(orient, elev)
  global heclair
  heclair = light('color',[eclair eclair eclair]);  % source de lumière blanche
end


function g3d_orient(h,e, elevation)
  orientation = get(h, 'value') ;
  view(orientation, elevation)  
end


function g3d_eclair(h,e)
  global heclair
  eclair = get(h, 'value') ;
  set(heclair, 'color',[eclair eclair eclair])
end

% ***** Aide et Sortie *************************************************************************************************

function infos(h,e)
  dialog_init
  texte = sprintf([ ...
    'Cette application illustre la programmation d''une \n' ...
    'interface-utilisateur graphique (GUI) sous MATLAB \n' ...
    'ou Octave GUI. \n\n' ...
    'Elle s''execute de façon "modale" en interagissant avec \n' ...
    'les menus (au haut de le fenetre) et boutons. \n' ...
  ]);
  uicontrol('style','text', 'string',texte, 'units','normalized', 'position',[.05 .4 .9 .4], ...
        'horizontalalignment','left', 'fontsize',13);
end


function quitter(h,e)
  uicontrol('style','text', 'string','Au revoir !', 'units','normalized', 'position',[.3 .05 .4 .1], ...
        'horizontalalignment','center', 'fontsize',25, 'backgroundcolor',[.8 .8 .8]);
  pause(1)
  close(gcf)  % ou: delete(gcf)
end

% **********************************************************************************************************************



Documentation © CC BY-SA 4.0 / / EPFL / Rév. 16-09-2021       ↵ Table des matières