6

I have a for loop in the opening function of a GUI in MATLAB and I'm trying to use a callback button to break the loop. I'm new to MATLAB. Here's the code I have:

%In the opening function of the GUI
handles.stop_now = 0;
for i=1:inf
   if handles.stop_now==1
      break;
   end
end


% Executes on button press 
function pushbutton_Callback(hObject, eventdata, handles)
% hObject    handle to end_segmenting_button (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
handles.stop_now=1;
guidata(hObject, handles);

For some reason, despite defining the variables with handles, the loop doesn't break upon pressing the button. Anyone know what's going on? Thanks.

Nick
  • 63
  • 1
  • 1
  • 3

2 Answers2

8

The problem you are having is that the structure of values passed to the opening function for handles is fixed at whatever it was when the opening function was called. You never retrieve the new structure that is updated by pushbutton_Callback. You can retrieve the new structure by calling GUIDATA in your loop. Here's how I would suggest you try writing your loop:

handles.stop_now = 0;  %# Create stop_now in the handles structure
guidata(hObject,handles);  %# Update the GUI data
while ~(handles.stop_now)
  drawnow;  %# Give the button callback a chance to interrupt the opening function
  handles = guidata(hObject);  %# Get the newest GUI data
end

The larger GUI design issue...

Based on the additional description in your comment about what you are trying to accomplish with your GUI, I think there may be a better way to design it. Instead of having a continuous loop for the user to repeatedly enter ROIs, which they then have to press a button to stop, you can do away with the loop and the stop button and add an "Add an ROI" button to your GUI. This way, the user can just press a button when they want to add another ROI. You can first replace the for loop in the opening function with the following initializations:

handles.nROIs = 0;  %# Current number of ROIs
handles.H = {};  %# ROI handles
handles.P = {};  %# ROI masks
guidata(hObject,handles);  %# Update the GUI data

Then you can replace the callback for your button with something like the following:

function pushbutton_Callback(hObject,eventdata,handles)
%# Callback for "Add new ROI" button
  nROIs = handles.nROIs+1;  %# Increment the number of ROIs
  hROI = imfreehand;  %# Add a new free-hand ROI
  position = wait(hROI);  %# Wait until the user is done with the ROI
  handles.nROIs = nROIs;  %# Update the number of ROIs
  handles.H{nROIs} = hROI;  %# Save the ROI handle
  handles.P{nROIs} = hROI.createMask;  %# Save the ROI mask
  guidata(hObject,handles);  %# Update the GUI data
end
gnovice
  • 125,304
  • 15
  • 256
  • 359
  • I see, so the key is to call GUIDATA within the loop. I'm actually running into another problem now. I'm using the for loop to capture ROIs from an image with imagefreehand. for i=1:inf drawnow handles = guidata(hObject); if handles.stop_now==1 break; end handles.H{i} = imfreehand; handles.P{i}= handles.H{i}.createMask; end The problem is, once I call the pushbutton, I can only exit the loop once I've selected one additional freehand region. How can I get around that? – Nick Dec 24 '10 at 04:27
  • 1
    In your implementation `break` exits the loop and control flow goes to `imfreehand()`. Therefore you should use `return` instead of `break`. – Mikhail Poda Dec 24 '10 at 08:16
  • Thanks for all the help. The thing is, I'm using the program to segment biological images. In one image, I might need to segment up to 20 distinct objects, so I'd rather not have the user push a button every time he/she needs to add an additional ROI. I just wonder if there's any way to get around the problem I'm having with the current set-up. – Nick Dec 25 '10 at 21:11
4

I see two potential problems here.

First: variable handles is not a reference, setting handles.stop_now=1; is going "lost" after control flow exits pushbutton_Callback. Use guidata or other approaches to store and retrieve data.

Second problem: Use function drawnow(). See this article of Yair Altman for good explanation.

Summary: MATLAB graphics is Java Swing and IO operations (like pressing a button) happen on a special thread - Event Dispatch Thread (EDT). Calling drawnow(); flushes event queue and updates figure window.

Community
  • 1
  • 1
Mikhail Poda
  • 5,742
  • 3
  • 39
  • 52
  • I am using guidata, and I've checked to make sure that handles.stop_now updates outside of the pushbutton_Callback (ie, I know it's not getting lost), but for some reason it's not recognized in the for loop... – Nick Dec 23 '10 at 22:03