2008-11-07 8 views
5

Est-il possible d'écrire une interface graphique à l'intérieur d'une fonction?Comment créer une interface graphique à l'intérieur d'une fonction dans MATLAB?

Le problème est que le rappel de toutes les fonctions GUI est évalué dans l'espace de travail global. Mais les fonctions ont leur propre espace de travail et ne peuvent pas accéder aux variables dans l'espace de travail global. Est-il possible de faire en sorte que les fonctions de l'interface graphique utilisent l'espace de travail de la fonction? Par exemple:

function myvar = myfunc() 
    myvar = true; 
    h_fig = figure; 

    % create a useless button 
    uicontrol(h_fig, 'style', 'pushbutton', ... 
         'string', 'clickme', ... 
         'callback', 'myvar = false'); 

    % wait for the button to be pressed 
    while myvar 
     pause(0.2); 
    end 

    close(h_fig); 

    disp('this will never be displayed'); 
end 

Cette boucle d'événement sera exécuté indéfiniment, car le rappel ne modifiera pas myvar dans la fonction. Au lieu de cela, il va créer un nouveau myvar dans l'espace de travail global.

Répondre

5

build a GUI Il existe plusieurs façons d'utiliser build a GUI, par exemple en utilisant le Concepteur d'applications, le GUIDE ou en le créant par programmation (je vais illustrer cette option ci-dessous). Il est également important de connaître le different ways to define callback functions pour vos composants GUI et le options available for sharing data between components.

L'approche à laquelle je suis parti utilise nested functions comme rappels. Voici une interface graphique simple exemple:

function make_useless_button() 

    % Initialize variables and graphics: 
    iCounter = 0; 
    hFigure = figure; 
    hButton = uicontrol('Style', 'pushbutton', 'Parent', hFigure, ... 
         'String', 'Blah', 'Callback', @increment); 

    % Nested callback function: 
    function increment(~, ~) 
    iCounter = iCounter+1; 
    disp(iCounter); 
    end 

end 

Lorsque vous exécutez ce code, le compteur affiché doit s'incrémenter chaque fois que vous appuyez sur la touche, car la fonction imbriquée increment a accès à l'espace de travail make_useless_button et peut ainsi modifier iCounter. Notez que le rappel de bouton est défini sur function handle à increment et que cette fonction doit accepter deux arguments par défaut: un handle de graphique pour le composant d'interface utilisateur qui a déclenché le rappel et une structure de données d'événement associées. Nous ignore them with the ~ dans ce cas puisque nous ne les utilisons pas.

Extension de l'approche ci-dessus à votre problème particulier, vous pouvez ajouter votre boucle et changer la fonction de rappel il définit votre variable de drapeau false:

function make_stop_button() 

    % Initialize variables and graphics: 
    keepLooping = true; 
    hFigure = figure; 
    hButton = uicontrol('Style', 'pushbutton', 'Parent', hFigure, ... 
         'String', 'Stop', 'Callback', @stop_fcn); 

    % Keep looping until the button is pressed: 
    while keepLooping, 
    drawnow; 
    end 

    % Delete the figure: 
    delete(hFigure); 

    % Nested callback function: 
    function stop_fcn(~, ~) 
    keepLooping = false; 
    end 

end 

Le drawnow est nécessaire ici pour donner le rappel touche une chance pour interrompre le flux du programme dans la boucle et modifier la valeur de keepLooping.

1

Vous pouvez déclarer une variable globale dans votre fonction et globale dans le code de l'interface graphique, certainement si le rappel est dans une fonction distincte plutôt qu'inline. Je l'ai fait dans une petite interface graphique squelette que j'utilise pour faire un système de menu rapide.

Dans votre code ci-dessus, vous pourrez peut-être ajouter le mot-clé global à votre déclaration initiale et également à votre ligne de rappel dire « global myvar = false »

+0

OP devra changer la variable de sortie en quelque chose d'autre et créer "global myvar" dans l'espace de travail de base pour que cela fonctionne. – Azim

+0

Est-ce vraiment le seul moyen? Il semble que ce soit un peu franc d'utiliser les variales mondiales pour le travail. – bastibe

+0

C'est la meilleure façon dont je suis arrivé - je suis d'accord c'est un peu moche, je ne pense pas que le modèle de l'interface graphique de Matlab soit très bon. Vous pourriez vouloir vérifier le code dans la contribution de uitable (?) Sur Mathworks. Le site est en panne à la minute. –

1

je trouve une solution au problème. La fonction de rappel doit modifier la structure de la poignée de l'interface graphique. Cette structure est accessible à la fois à partir du rappel et de la fonction sans introduire de nouvelles variables à l'espace de travail global:

function myfunc() 
    h_fig = figure; 

    % add continue_loop to the GUI-handles structure 
    fig_handles = guihandles(h_fig); 
    fig_handles.continue_loop = true; 
    guidata(h_fig, fig_handles); 

    % create a useless button 
    uicontrol(h_fig, 'style', 'pushbutton', ... 
         'string', 'clickme', ... 
         'callback', @gui_callback); 

    % wait for the button to be pressed 
    while fig_handles.continue_loop 
     fig_handles = guidata(h_fig); % update handles 
     pause(0.2); 
    end 

    close(h_fig); 
    disp('callback ran successfully'); 
end 

% The arguments are the Matlab-defaults for GUI-callbacks. 
function gui_callback(hObject, eventdata, handles) 
    % modify and save handles-Structure 
    handles.continue_loop = false; 
    guidata(hObject, handles); 
end 

noter que depuis la boucle while ne met à jour fig_handles lorsqu'il est exécuté, vous aurez toujours fig_handles.continue_loop

+0

La réponse que vous avez donnée ici semble certainement correcte, et c'est ainsi que beaucoup de gens gèrent probablement ce genre de problème. Tout est une question de préférence personnelle: certaines personnes aiment utiliser GUIDE, alors que j'ai toujours pensé que je pouvais rendre les choses plus propres avec des fonctions imbriquées (c'est un peu plus de travail, cependant). – gnovice

+0

Je seconde cela. En fait, j'ai tellement souffert du code généré par GUIDE, que j'ai écrit fig2cmd - pour extraire d'un fichier .fig les commandes nécessaires pour le reproduire dans un fichier m. –

Questions connexes