How do I interrupt a while loop with recursive, interrupting callback of checkbox in GUI

Hi all,
I have a GUI designed to record mouseclicks on an axis. The recording should start when I push a checkbox (Value==1 is true), and end when I push the checkbox again (Value==0 is true)
My code follows, and currently does the job, but it is unsatisfying. My current workaround centers around the line:
pause(0.3) %Allow interrupting callbacks to execute
However, this line is very finicky. Changing it to "pause(0.05)" results in the while loop finishing before the interrupting callback, and the code gets stuck on waitforbuttonpress even after completion of the interrupting callback. I've tried "drawnow" as well, with similar unintended results (code prematurely finishes while loop and gets "stuck" on waitforbuttonpress on the next unintended loop).
Am I missing something? Trying to write good code that doesn't involve an artificial pause for 0.3 seconds for interrupting callbacks to "catch up."
function record_cb_Callback(hObject, eventdata, handles)
if hObject.Value==1 %Executed on first checkbox click.
handles.stoprecord=0;
guidata(hObject,handles);
while handles.stoprecord ==0;
waitforbuttonpress %Could be in axes1 or on current checkbox
pause(0.3) %Allow interrupting callbacks to execute
handles = guidata(hObject);
%This is what I'm trying to record, but is not pertinent to
%question
if handles.newaxclick
handles.deformFuncX = [handles.deformFuncX, handles.axClickX];
handles.deformFuncY = [handles.deformFuncY, handles.axClickY];
handles.newaxclick=0;
end
guidata(hObject,handles);
end
elseif hObject.Value==0 %Executed on recursive interrupting callback
handles.stoprecord = 1; %This needs to execute before the whileloop in the first callback completes
guidata(hObject,handles);
end
%For completeness, here is a related callback used in recording my axis
%clicks
function axes1_ButtonDownFcn(hObject, eventdata, handles)
handles.axClickX = hObject.CurrentPoint(1,1);
handles.axClickY = hObject.CurrentPoint(1,2);
handles.newaxclick = 1; %Tell other callbacks to react to a click in the axis. Other callbacks must reset back to 0.
guidata(hObject,handles);

 Accepted Answer

Peter - perhaps consider not using a while loop. The purpose of the loop seems only to update your two arrays of x and y coordinates for the mouse button down events. If this is the case, why not "record" these positions as soon as you press the mouse button? In the _OpeningFcn of your GUI, initialize two arrays for these coordinates as
function AxesMouseClickExampleGui_OpeningFcn(hObject, eventdata, handles, varargin)
% Choose default command line output for AxesMouseClickExampleGui
handles.output = hObject;
handles.axesClickX = [];
handles.axesClickY = [];
% Update handles structure
guidata(hObject, handles);
In your checkbox callback, just clear out these arrays when the checkbox has been selected
function checkbox1_Callback(hObject, eventdata, handles)
if get(hObject,'Value') == 1
set(hObject,'String','Stop Recording');
handles.axesClickX = [];
handles.axesClickY = [];
guidata(hObject,handles);
else
handles.axesClickX
handles.axesClickY
set(hObject,'String','Start Recording');
end
So if the user checks the checkbox, we change the text to "Stop Recording" and empty the arrays. If the user deselects the checkbox, then we change the text to "Start Recording" and write out the two arrays of coordinates.
In the button down callback (for your axes) we capture the current point and record it only if the user has checked the checkbox
function axes1_ButtonDownFcn(hObject, eventdata, handles)
if get(handles.checkbox1,'Value') == 1
currentPos = get(hObject,'CurrentPoint');
handles.axesClickX = [handles.axesClickX ; currentPos(1,1)];
handles.axesClickY = [handles.axesClickY ; currentPos(1,2)];
guidata(hObject,handles);
end
See the attached for an example.

1 Comment

Thanks Geoff,
Great point. I think recording the points from the axes buttondown callback is stylistically better than a while loop that relies on "outside" changes to guidata global variables to terminate, and this will probably be how I do it.
The initial reasoning for using the while loop was to create a new state in the GUI on checkbox click, where the user could only select points, and do nothing else until he clicked the checkbox again. Fortunately, I think I can do this with if/then or switch statements in other callbacks that check the value of the checkbox before executing.
Appreciate the help.

Sign in to comment.

More Answers (0)

Categories

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

Asked:

on 4 Jun 2016

Edited:

on 4 Jun 2016

Community Treasure Hunt

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

Start Hunting!