MATLAB: Problem with callback function “hanging” after certain number of times pressed

callbackImage Processing Toolboximpointmatlab hang

I am having an issue with a function that should allow the user to select a undefined number of points on a graph, and click done whenever the user decides all the relevant points are selected. I am having an issue where, after 19 "btnAdd" clicks, MATLAB "hangs" and will not let me click anything else. I have added print statements at the beginning of my callback which do not execute, making it seem that the callback is never called on the 20th click. I have also tried using drawnow and pause(0.2), etc. to get rid of the hang problem as recommended in different answers. Here is an example of the code without any extraneous details.
function testAddButton
close all;
x = [1:1:100];
y = rand([100,1]);
plot(x,y, 'm');
handles = guidata(gcf);
handles.impointArray = impoint.empty;
guidata(gcf, handles);
btnAdd = uicontrol('String','Add point',...
'Position',[90 60 70 30],...
'Callback', @addCallbackFunction,...
'BusyAction', 'cancel',...
'Interruptible', 'off');
btnDone = uicontrol('String','Done',...
'Position',[165 60 40 30],...
'Callback', 'uiresume(gcbf); drawnow; pause(0.05);');
uiwait(gcf); % wait until 'Done' is pressed
drawnow; pause(0.05);
delete(btnAdd); % remove the button

delete(btnDone); % remove the button
handles.guidata(gcf)
end
function addCallbackFunction(gcf, eventdata, handles)
handles = guidata(gcf);
impointArray = handles.impointArray;
impointArray(end+1) = impoint(gca);
handles.impointArray = impointArray;
guidata(gcf, handles);
uiwait(gcbf);
end
When MATLAB is hanging, I can Ctrl-C and I get this message:
??? Operation terminated by user during ==> uiwait at 73
In ==> testAddButton>addCallbackFunction at 36
uiwait(gcbf);
??? Error using ==> waitfor
Interrupt while evaluating uicontrol Callback.
??? Operation terminated by user during ==> uiwait at 73
In ==> manageInteractivePlacement at 93
uiwait(h_fig);
In ==> impoint>impointAPI at 247
placement_aborted =
manageInteractivePlacement(h_axes,h_group,@placePoint);
In ==> impoint>impoint.impoint at 90
[h_group,draw_api] = impointAPI(varargin{:});
In ==> testAddButton>addCallbackFunction at 33
impointArray(end+1) = impoint(gca);
??? Error using ==> waitfor
Interrupt while evaluating uicontrol Callback.
??? Operation terminated by user during ==> uiwait at 73
In ==> testAddButton>addCallbackFunction at 36
uiwait(gcbf);
??? Error using ==> waitfor
Interrupt while evaluating uicontrol Callback.
I am using MATLAB R2011A. Thanks so much!

Best Answer

  • kaycraw - since you are programmatically creating your GUI, there are a couple of things that you can do to simplify the above. Rather than having your main function and your callback separate, you can nest the latter into the former so that it can access all local variables defined in the parent function. That way you can avoid the use of the handles structure (which is more of a GUIDE GUI "feature") and just access the variables as you need them. For example, the above code can be rewritten as
    function testAddButton
    close all;
    x = [1:1:100];
    y = rand([100,1]);
    plot(x,y, 'm');
    pointArray = [];
    btnAdd = uicontrol('String','Add point',...
    'Position',[90 60 70 30],...
    'Callback', @addPointBtnCallback);
    btnDone = uicontrol('String','Done',...
    'Position',[165 60 40 30],...
    'Callback', @doneBtnCallback);
    function addPointBtnCallback(hObject, eventdata)
    newPoint = ginput(1);
    pointArray = [pointArray ; newPoint];
    end
    function doneBtnCallback(hObject, eventdata)
    fprintf('%f %f\n',pointArray');
    delete(btnAdd);
    delete(btnDone);
    end
    end
    Note how the pointArray variable is declared within the testAddButton function but can still be accessed in the nested (callback) functions. Also, the use of the uiwait and uiresume have been removed since we can use the doneCallback to delete the controls from our figure. (I used ginput in place of impoint since I don't have the Image Processing Toolbox, but the idea will be the same.)
    Try the above and see what happens!
    As an aside, your signature for the * addCallbackFunction* is defined as
    function addCallbackFunction(gcf, eventdata, handles)
    The first input parameter is named gcf. This is the name of a built-in MATLAB function (get current figure) and so you should avoid naming your own variables like this. Also, the third input parameter, handles, is likely never initialized. Outside of GUIDE, callbacks typically have only the object handle and event data input parameters. You can add more, but you need to do this explicitly.