Passage de données aux fonctions callback

La structure classique d'un programme qui génère une interface graphique comporte une fonction principale (qui porte le nom du fichier m-file) et un ensemble d'autre fonctions, y compris les fonction callback des objets graphiques.
Les objet graphique sont en général crée dans la fonction principale. Leurs identificateurs sont donc connus de celle-ci. Le problème se pose quand les autres fonctions ont besoin d'accéder au objets graphiques, ils ont besoin de leurs identificateurs. L'objectif de cette section est de monter comment la fonction principale peut partager ces identificateurs avec les autres fonctions.

Fonctions imbriquées

Une fonction imbriquée (nested function) dans une autre fonction partage ses variables. Elle peut les lire et les modifier. Donc, si toutes les fonctions callback sont imbriquées dans la fonction principale, elles auront accès à toutes ses variables y compris les identificateurs (handles) des objet graphiques.
C'est la méthode la plus simple, mais elle demande quelques précautions dans la gestion des variable. Si, on crée une variable  dans une fonction pour un usage local, et par mégarde, on lui donne un nom déjà utilisé dans la fonction principale, on aura écrasé une variable existence sans faire attention, ce qui peux s'avérer néfaste pour le fonctionnement du programme.

Exemple
function handles_nested()
    % Utilisation des fonctions imbriquése pour partager les données avec la
    % fonction principale
    close all
    fh = figure('Units', 'Normalized', 'Position',[0.6 0.6 0.15 0.15], 'MenuBar', 'none');
    set(0, 'DefaultUicontrolUnits',  'normalized') ;
    e1 = uicontrol(fh, 'style', 'EDIT', 'Posit',[0.5 0.7 0.3 0.2], 'str', 22);
    e2 = uicontrol(fh, 'style', 'Edit', 'Posit',[0.5 0.4 0.3 0.2], 'str', '44');
    e3 = uicontrol(fh, 'style', 'EDIT', 'Posit',[0.5 0.1 0.3 0.2]);
    b1 = uicontrol(fh, 'style', 'pushbutton', 'position',[0.1 0.4 0.3 0.2],...
        'str', 'Alpha', 'call', @alphaa);
    b2 = uicontrol(fh, 'style', 'pushbutton', 'position',[0.1 0.1 0.3 0.2],...
        'str', 'Num', 'call', @numm);

    function numm(obj,event)
        n1 = str2num(get(e1, 'string'));
        n2 = str2num(get(e2, 'string'));
        set(e3, 'string',n1+n2);
    end

    function alphaa(obj,event)
        s1 = get(e1, 'string');
        s2 = get(e2, 'string');
        set(e3, 'string',[s1 s2]);
    end

end


Variables globales

Une autre solution consiste à ne pas utiliser les fonctions imbriquées mais de déclarer des variables globales.
J'ai cru comprendre (à travers le web) que les puritains n'aiment pas trop cette solution. Pour ma part, je ne lui trouve pas vraiment de grands inconvénients, surtout pour une application de petite taille.
Avec cette solution, chaque fonction a ses variables locales. Les variables locales de plusieurs fonctions peuvent porter le même nom tout en étant tout à fait indépendantes les unes des autres.

Exemple:
function handle_global()
    global e1 e2 e3
    close all

    fh = figure('Units', 'Normalized', 'Position',[0.6 0.6 0.15 0.15],...
        'MenuBar', 'none');
    set(0, 'DefaultUicontrolUnits',  'normalized') ;
    e1 = uicontrol(fh, 'style', 'EDIT', 'Posit',[0.5 0.7 0.3 0.2], 'str', 22);
    e2 = uicontrol(fh, 'style', 'Edit', 'Posit',[0.5 0.4 0.3 0.2], 'str', '44');
    e3 = uicontrol(fh, 'style', 'EDIT', 'Posit',[0.5 0.1 0.3 0.2]);
    b1 = uicontrol(fh, 'style', 'pushbutton', 'position',[0.1 0.4 0.3 0.2],...
        'str', 'Alpha', 'call', @alphaa);
    b2 = uicontrol(fh, 'style', 'pushbutton', 'position',[0.1 0.1 0.3 0.2],...
        'str', 'Num', 'call', @numm);
end

function numm(obj,event)
    global e1 e2 e3
    n1 = str2num(get(e1, 'string'));
    n2 = str2num(get(e2, 'string'));
    set(e3, 'string',n1+n2);
end

function alphaa(obj,event)
    global e1 e2 e3
    s1 = get(e1, 'string');
    s2 = get(e2, 'string');
    set(e3, 'string',[s1 s2]);
end



Passage de paramètres

Une autre solution consiste à passer des paramètres aux fonctions au moment de les appeler

Exemple:
function handle_param()
    % passage des handles comme paramètres au moment de l'appel des fonctions
    close all
    fh = figure('Units', 'Normalized', 'Position',[0.6 0.6 0.15 0.15],...
        'MenuBar', 'none');
    set(0, 'DefaultUicontrolUnits',  'normalized') ;
    e1 = uicontrol(fh, 'style', 'EDIT', 'Posit',[0.5 0.7 0.3 0.2], 'str', 22);
    e2 = uicontrol(fh, 'style', 'Edit', 'Posit',[0.5 0.4 0.3 0.2], 'str','44');
    e3 = uicontrol(fh, 'style', 'EDIT', 'Posit',[0.5 0.1 0.3 0.2]);
    b1 = uicontrol(fh, 'style', 'pushbutton', 'position',[0.1 0.4 0.3 0.2],...
        'str', 'Alpha', 'callback', {@alphaa e1 e2 e3});
    b2 = uicontrol(fh, 'style', 'pushbutton', 'position',[0.1 0.1 0.3 0.2],...
        'str', 'Num', 'callback', {@numm e1 e2 e3});
end

function numm(obj,event, e1, e2, e3)
    n1 = str2num(get(e1, 'string'));
    n2 = str2num(get(e2, 'string'));
    set(e3, 'string',n1+n2);
end

function alphaa(obj,event, e1, e2, e3)
    s1 = get(e1, 'string');
    s2 = get(e2, 'string');
    set(e3, 'string',[s1 s2]);
end


Si on a beaucoup de variables à passer, on peut les regrouper dans une structure et passer le nom de la structure

Exemple:
function handle_param_struct()
    % les handle sont groupés dans une structure qui est passée en
    % paramètre au fonctions appelées
    close all
    fh = figure('Units', 'Normalized', 'Position',[0.6 0.6 0.15 0.15],...
        'MenuBar', 'none');
    set(0, 'DefaultUicontrolUnits',  'normalized') ;
    hs.e1 = uicontrol(fh, 'style', 'EDIT', 'Posit',[0.5 0.7 0.3 0.2], 'str', 22);
    hs.e2 = uicontrol(fh, 'style', 'Edit', 'Posit',[0.5 0.4 0.3 0.2], 'str', '44');
    hs.e3 = uicontrol(fh, 'style', 'EDIT', 'Posit',[0.5 0.1 0.3 0.2]);
    b1 = uicontrol(fh, 'style', 'pushbutton', 'position',[0.1 0.4 0.3 0.2],...
        'str', 'Alpha', 'call', {@alphaa hs});
    b2 = uicontrol(fh, 'style', 'pushbutton', 'position',[0.1 0.1 0.3 0.2],...
        'str', 'Num', 'call', {@numm hs});
end

function numm(obj,event, ids)
    n1 = str2num(get(ids.e1, 'string'));
    n2 = str2num(get(ids.e2, 'string'));
    set(ids.e3, 'string',n1+n2);
end

function alphaa(obj,event, ids)
    s1 = get(ids.e1, 'string');
    s2 = get(ids.e2, 'string');
    set(ids.e3, 'string',[s1 s2]);
end



La fonction guidata()

La fonction guidata() permet de sauvegarder/restaurer des variables dans l'espace de travail de l'interface graphique.

Là aussi, il est préférable de regrouper les variables dans une structure, ce qui revient à sauvegarder plusieurs variables d'un coup.  Il existe une fonction appelée guihandles() qui permet de créer une structure d'identificateurs d'objets. Nous allons nous en passer car elle n'apporte pas grand chose à moins d'utiliser la propriété tag lors de la création des objets graphiques.

Exemple:
function handle_guidata()
    close all
    fh = figure('Units', 'Normalized', 'Position',[0.6 0.6 0.15 0.15], 'MenuBar', 'none');
    set(0, 'DefaultUicontrolUnits',  'normalized') ;
    hs.e1 = uicontrol(fh, 'style', 'EDIT', 'Posit',[0.5 0.7 0.3 0.2], 'str', 22);
    hs.e2 = uicontrol(fh, 'style', 'Edit', 'Posit',[0.5 0.4 0.3 0.2], 'str', '44');
    hs.e3 = uicontrol(fh, 'style', 'EDIT', 'Posit',[0.5 0.1 0.3 0.2]);
    b1 = uicontrol(fh, 'style', 'pushbutton', 'position',[0.1 0.4 0.3 0.2],...
        'str', 'Alpha', 'call', @alphaa);
    b2 = uicontrol(fh, 'style', 'pushbutton', 'position',[0.1 0.1 0.3 0.2],...
        'str', 'Num', 'call', @numm);
    guidata(fh, hs);
end

function numm(obj,event)
    ids = guidata(obj);
    n1 = str2num(get(ids.e1, 'string'));
    n2 = str2num(get(ids.e2, 'string'));
    set(ids.e3, 'string',n1+n2);
end

function alphaa(obj,event)
    hndl = guidata(obj);
    s1 = get(hndl.e1, 'string');
    s2 = get(hndl.e2, 'string');
    set(hndl.e3, 'string',[s1 s2]);
end