2016-07-14 1 views
-1

Mon programme exécute une fonction lorsque l'utilisateur clique sur un objet axes. Cette fonction utilise la position du curseur et montre sa progression en tant qu'animation. Ce dont j'ai besoin, c'est d'arrêter l'appel de fonction en cours lorsque l'utilisateur clique sur une nouvelle position, puis d'appeler la fonction pour cette nouvelle position.Comment attendre la fin d'une fonction en cours dans une fonction de rappel gui?

Mon code est quelque chose comme ça (dans mon code original que j'utilise guidata et handles au lieu des variables globales):

function TestUI 
clc; clear variables; close all; 
figure; axis equal; hold on; 
xlim([0 100]); ylim([0 100]); 
set(gca, 'ButtonDownFcn', @AxisButtonDownFcn); 
global AnimateIsRunning 
AnimateIsRunning = false; 
end 

function AxisButtonDownFcn(ah, ~) 
C = get(gca,'CurrentPoint'); 
global xnow ynow AnimateIsRunning 
xnow = C(1, 1); ynow = C(1, 2); 
if AnimateIsRunning 
    % ---> I need to wait for termination of currently running Animate 
end; 
Animate(ah, xnow, ynow); 
end 

function Animate(ah, x, y) 
T = -pi:0.02:pi; r = 5; 
global xnow ynow AnimateIsRunning 
AnimateIsRunning = true; 
for t = T 
    if ~((xnow==x)&&(ynow==y)) 
     return; 
    end; 
    ph = plot(ah, x+r*cos(t), y+r*sin(t), '.'); 
    drawnow; 
    delete(ph) 
end 
AnimateIsRunning = false; 
end 

Mon problème est que les clics nouvelles interruption fonction en cours d'exécution et continue à tourner précédente Animate dans une pile. Cela rend le dernier dessin de l'animation précédente visible. Le pire est que la taille de la pile semble être 8 et les nouvelles interruptions seront stockées dans une file d'attente ! Ce qui signifie que l'utilisateur peut mettre à jour la position seulement 8 fois. Pour voir le problème, vous pouvez exécuter l'exemple de code ci-dessus et cliquer plusieurs fois sur l'objet axes.

Maintenant, je veux vérifier si Animate est en cours d'exécution dans AxisButtonDownFcn, et attendre sa fin (ou le terminer par la force), puis appelez Animate avec de nouveaux paramètres.

+0

Voulez-vous désactiver les nouveaux clics jusqu'à ce que ce soit fait? – Suever

+0

@Suever Non, je veux attendre 'Animate' pour finir son travail, il va vérifier' xnow' et 'ynow' dans l'itération suivante et revenir. – saastn

Répondre

0

Comme memyself répondit le other question, il est impossible de mettre fin en cours d'exécution Animate[ou en attente de sa terminaison], parce que les deux AxisButtonDownFcn et Animate sont appelés en même thread. Ainsi, les options disponibles sont:

  1. En utilisant variables globales, ce qui est simple à mettre en œuvre, mais ajoute à la complexité et les dépendances mutuelles. Vous pouvez trouver des solutions difficiles here et here.
  2. Multi-threading, qui tente d'exécuter des interactions de section de traitement et d'interface utilisateur dans des threads distincts. Ce sera plus robuste (si vous avez l'habitude de travailler avec des threads), mais vous aurez besoin de plus de codage. Il existe des implémentations détaillées pour ce here.

Ma solution est basée sur l'utilisation de variables globales. Il est vraiment comme les solutions que je l'ai déjà lié, mais les deux tentent de mettre en œuvre des boutons marche/arrêt, alors que je dois arrêter de processus en cours et commencer une nouvelle en même temps:

function TestUI 
clc; clear variables; close all; 
figure; axis equal; hold on; 
xlim([0 100]); ylim([0 100]); 
set(gca, 'ButtonDownFcn', @AxisButtonDownFcn); 
global AnimateIsRunning 
AnimateIsRunning = false; 
end 

function AxisButtonDownFcn(ah, ~) 
C = get(gca,'CurrentPoint'); 
global xnow ynow AnimateIsRunning 
xnow = C(1, 1); ynow = C(1, 2); 
if ~AnimateIsRunning 
    Animate(ah); 
end; 
end 

function Animate(ah) 
T = -pi:0.02:pi; r = 5; 
global xnow ynow AnimateIsRunning 
AnimateIsRunning = true; 
x = -1; y = -1; 
while ~((x==xnow)&&(y==ynow)) 
    x = xnow; y = ynow; 
    for t = T 
     if ~((xnow==x)&&(ynow==y)) 
      break; 
     end; 
     if ishandle(ah) 
      ph = plot(ah, x+r*cos(t), y+r*sin(t), '.'); 
      drawnow; 
      if ishandle(ph) 
       delete(ph) 
      end 
     end 
    end 
end; 
AnimateIsRunning = false; 
end 

Il suffit empêcher Animate d'être appelé deux fois. Il appelle Animate s'il n'est pas en cours d'exécution, sinon, il informe simplement en cours d'exécution Animate qu'il existe une nouvelle demande.