Using a Matlab GUI Button to Halt a running callback

21 views (last 30 days)
I have a Matlab GUI with a button initially called 'Run'. When I hit that button a loop is started that does some processing, and I change the name of the button to 'Halt'. When the 'Halt' button is pressed, I want the GUI to recognize the button press, and halt the callback that is running. So my question is, is there any property of a Button that I can use that will be changed when my user hits my button the 2nd time? (If I can detect the button has been pressed, then I can halt the running loop).

Accepted Answer

Joseph Cheng
Joseph Cheng on 4 Sep 2014
This can be done but for ease i would change to a toggle button. Save the below code as a whole under opti.m and then run it. without spending too much time i was trying to do it with a push button and update flags but haven't had to time to think through the handle update flow. however since the toggle button is handled at the handle level (MATLAB employees please correct me on that) and not running another function to update a value it will update while in the loop.
function opti();
fig = figure;
ax = axes;
axis([0 100 -5 5]);
b = uicontrol('Style', 'togglebutton', 'String', 'RUN',...
'Position', [20 20 50 20],...
'Callback', {@buttonpress,ax});
end
function buttonpress(hObject,event,ax)
switch get(hObject,'Value')
case 0
set(hObject,'String','HALT')
case 1
set(hObject,'String','RUN')
cla(ax);
end
axes(ax)
hold on;
t=0;
while get(hObject,'Value') || t>30;
t=t+1;
y=sin(2*pi*t/10);
plot(t,y,'.');
pause(.1);
end
end

More Answers (2)

Geoff Hayes
Geoff Hayes on 4 Sep 2014
Michael - I don't think that you can have a button interrupt its own callback through a call to the callback, which is kind of what you want to do (or at least that is my interpretation of your question). I tried playing around with the push button and the toggle button widgets, and while I could get the callback to fire a second time, it had no real impact on the first callback which is still going because of the while or for loop. If you were using a timer instead (to do the periodic work) then you could do something on the second call to stop the timer.
For your question, is there any property of a Button that I can use that will be changed when my user hits my button the 2nd time, you do kind of know that it is the second time that the button has been pushed because of the button string value - either it is Start (first button press) or Halt (second button press). So you could do something in the callback that checks the "state" of the string value and if the first button press, then start the loop; and if the second button press, then somehow flag the first callback call to stop. It can be done (and I just mocked up something for it) but I would counsel against this sort of coding. It seems clumsy and probably prone to errors.
I would suggest that you just add a second button called Halt that, when pressed, would interrupt the Start button callback and set some sort of flag that the first callback would recognize and force itself to break out of the loop. We can interrupt the first callback if in its loop there is call to one of drawnow, figure, getframe, pause, or waitfor (see interrupt callback execution for details).
Suppose you have two push buttons called start and halt. Then the callback for the start button could be something like
function start_Callback(hObject, eventdata, handles)
% disable the start button
set(hObject,'Enable','off');
% enable the halt button
set(handles.halt,'Enable','on');
% flag that the loop is running
handles.doLoop = true;
guidata(hObject,handles);
% start loop
fprintf('starting while loop\n');
while true
% do stuff
pause(0.001);
% should we continue?
handles = guidata(hObject);
if ~handles.doLoop
break;
end
end
fprintf('exiting while loop\n');
% enable the start button
set(hObject,'Enable','on');
% disable the halt button
set(handles.halt,'Enable','off');
All it does is enables and disables buttons as it sees fit, creates a flag that is set to true to indicate that the loop should be executed ( doLoop ), and does the loop. At each pass through the loop, it grabs the latest handles data and checks the doLoop flag. Once it is set to false, then we exit the loop and we're done. Note that I've included the pause command so that this callback can be interrupted.
The halt callback is much simpler: it just sets the doLoop flag to false.
function halt_Callback(hObject, eventdata, handles)
% flag that the loop should be stopped
handles.doLoop = false;
guidata(hObject,handles);
Try the above. Note that you may still need to add some extra logic to handle the case where the user tries to close the GUI (via the x button). The loop will still be running, and so should be interrupted in a manner similar to the user pressing the Halt button.

Michael
Michael on 5 Sep 2014
My thanks for the time both of you spent preparing your answers! I tried Joseph's opti.m function and he's got the behavior I was hoping to achieve, so it looks like using a single button to both start and stop a running process loop (in the button callback) is possible. I'm going to see if I can adapt his code for my situation. But Geoff should know, using a 2nd button for halt was something I'd thought of also, I'm just trying to minimize the number of controls to minimize the failure modes. Thank you both for your very timely relpies!
Mike

Categories

Find more on Interactive Control and Callbacks in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!