-1

My program runs a function when user clicks on an axes object. This function uses the position of cursor and shows its progress as an animation. What I need is to stop currently running call of function when user clicks a new position, and then call the function for this new position.

My code is something like this (in my original code I use guidata and handles instead of global variables):

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

My problem is that any newer clicks interrupt currently running function and keeps previous running Animate in a stack. It makes the last drawing of the previous animation remain visible. The worse is that the size of the stack seems to be 8 and newer interruptions will be stored in a queue! Meaning user can update position only 8 times. To see the problem you can run the code sample above and click on the axes object repeatedly.

Now, I want to check if Animate is running in AxisButtonDownFcn, and wait for its termination (or terminate it by force), and then call Animate with new parameters.

saastn
  • 5,717
  • 8
  • 47
  • 78

1 Answers1

0

As memyself answered the other question, it's impossible to terminate currently running Animate [or waiting for its termination], because both AxisButtonDownFcn and Animate are called in same thread. So available options are:

  1. Using global variables, which is simple to implement but adds complexity and mutual dependencies. You can find some tricky solutions here and here.
  2. Multi-threading, witch attempts to run processing section and UI interactions in separate threads. It'll be more robust (if you are experienced in working with threads), but needs more coding. There is a detailed implementations for this here.

My solution is based on use of global variables. It's really like the solutions I've already linked to, but both of them are trying to implement start/stop buttons, while I need to stop current process and start a new one at same time:

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

It simply prevent Animate from being called twice. It calls Animate if it's not running, otherwise, it just informs currently running Animate that there are new request.

Community
  • 1
  • 1
saastn
  • 5,717
  • 8
  • 47
  • 78