Problem with "cancel" button (waitbar). User input is ignored.

Hi folks
I'm a bit puzzled about an issue I (most likely) introduced into my code. The programme in question opens a relatively primitive GUI with a number of options to handle experimental data from our sensors. One of the buttons involves a spectral analysis (power spectral density and the like) of the data files located in the same directory as the MATLAB file (or a stand-alone executable). The data sets can be relatively large and thus the analysis can take some time. Misclicks happen, so I added a "Cancel" button to the progress bar (simple waitbar function, copied & pasted from MATHWORKS examples). This in turn opens another function deleting every figure and every output file the programme has created up to this point. As of late, the programme ignores me clicking the cancel button. Getappdata shows that the associated variable doesn't change and that the operator input is completely ignored.
I know the code is not winning any beauty contests, but it worked fine up until recently. There has been a major update involving some streamlining/restructuring in the core programme. I guess that I've screwed up somewhere and I was wondering if you guys could perhaps point me in the right direction?
Matlab version is R2011, however, the problem also occurs with the trial version of R2023. Used toolboxes are "signal processing" and "curve fitting".
Main structure looks like this:
function varargout = SW0110_Beta(varargin)
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, ...
'gui_Singleton', gui_Singleton, ...
'gui_OpeningFcn', @SW0110_Beta_OpeningFcn, ...
'gui_OutputFcn', @SW0110_Beta_OutputFcn, ...
'gui_LayoutFcn', [] , ...
'gui_Callback', []);
if nargin && ischar(varargin{1})
gui_State.gui_Callback = str2func(varargin{1});
end
if nargout
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
gui_mainfcn(gui_State, varargin{:});
end
%...
function SW0110_OpeningFcn(hObject, eventdata, handles, varargin)
handles.output = hObject;
guidata(hObject, handles)
%...
function varargout = SW0110_OutputFcn(hObject, eventdata, handles)
varargout{1} = handles.output;
%...
function pushbutton_Callback(hObject,~,handles)
%...
%Plus a few more functions like this
%...
A simple GUI with a couple of buttons and input lines put together in Guide. Nothing fancy. If the operator hits the "Compile" button in the main window we get to
function pushbutton_Callback(hObject,~,handles)
%...
%lots of data reading, handling and output generation
fwait_analyze = waitbar(0,'1','Name','Analysing Data - Please Wait','CreateCancelBtn','setappdata(gcbf,''canceling'',1)');
setappdata(fwait_analyze,'canceling',0);
waitbar(0,fwait_analyze,sprintf('0 %%'));
%...
%simple loop i=1:dat_numb
if getappdata(fwait_analyze,'canceling') == 1
%second loop v=1:i & second progress bar
fcancel = waitbar(0,'1','Name','Deleting OutPut Files - Please Wait');
waitbar(0,fcancel,sprintf('0 %%'));
%remove results/output files
waitbar(v/dat_numb,fcancel,sprintf('%2.0f %%',v/i*100-1))
%end v loop
%delete fwait_analyze & fcancel
return
end
waitbar(i/dat_numb,fwait_analyze,sprintf('%2.0f %%',i/dat_numb*100-1))
%end i loop
%...rest of the function
end
As simple as it gets with a second progress bar indicating the removal process. Any operator input (clicking the cancel button) is ignored and getappdata is always returning '0' in this framework. Running the code on its own works fine and the user input is properly recognized.
Not overly surprising, version 2 with uicontrol exhibits the same problem.
function pushbutton1_Callback(hObject,~,handles)
%...
fwait_analyze = waitbar(0,'1','Name','Analysing Data - Please Wait');
uicontrol('Parent',fwait_analyze,'Style','pushbutton','String','Cancel','Units','normalized','Position',[0.75 0.1 0.2 0.3],'Visible','on','CallBack',@CancelB);
waitbar(0,fwait_analyze,sprintf('0 %%'));
%...
%loop i=1:dat_numb
waitbar(i/dat_numb,fwait_analyze,sprintf('%2.0f %%',i/dat_numb*100-1))
%end i loop
%rest of the function
end
%...
function CancelB(~,~)
fcancel = waitbar(0,'1','Name','Deleting OutPut Files - Please Wait');
waitbar(0,fcancel,sprintf('0 %%'));
%loop v=1:dat_numb
%remove results/output files
waitbar(v/dat_numb,fcancel,sprintf('%2.0f %%',v/dat_numb*100-1))
%end v loop
%delete fwait_analyze & fcancel
return
end
The code here is just for indication to give you can idea what I'm trying to accomplish. I'm more interested in understanding why MATLAB is doing what it is doing. Any comment would be greatly appreciated.
Thanks a lot + kind regards
Christian

7 Comments

I am not sure, but maybe in the CancelB callback, you should find your fwait_analyze handle and set it to 1. Below is a link that will help you how to get its handle.
@Christian Bretschneider: The following code is an attempt to reproduce the problem. When I run it in R2016b, the problem doesn't happen. Can you try running it in your version, from the command line or in a script separate from your GUI, and see if it exhibits the problem? If not, then maybe something else in your GUI code is causing the problem.
dat_numb = 10000;
fwait_analyze = waitbar(0,'1','Name','Analysing Data - Please Wait','CreateCancelBtn','setappdata(gcbf,''canceling'',1)');
setappdata(fwait_analyze,'canceling',0);
waitbar(0,fwait_analyze,'0 %');
for i = 1:dat_numb
if getappdata(fwait_analyze,'canceling') == 1
fcancel = waitbar(0,'1','Name','Deleting Output Files - Please Wait');
waitbar(0,fcancel,'0 %');
for v = 1:i
waitbar(v/i,fcancel,sprintf('%2.0f %%',v/i*100));
end
delete(fwait_analyze);
delete(fcancel);
return
end
waitbar(i/dat_numb,fwait_analyze,sprintf('%2.0f %%',i/dat_numb*100));
end
if ishandle(fwait_analyze)
delete(fwait_analyze);
end
Good morning all
Sorry for the delay, but there was a holiday here on Monday.
@Mario Malic: Thank you for your reply. I tried, but I didn't see any effect. I added a simple output line (display) and it seems that the function is just never called when I'm within the GUI.
@Voss: Thank you. This was one of the first things I checked copying the two waitbar loops into a separate function (and running it from the command line). It worked as it should and so does the code above. However, as soon as I copy & paste it into my GUI I see the aforementioned problem. If you put the line
"getappdata(fwait_analyze,'canceling')"
into the loop the output stays "0" within the GUI when I press the cancel button. In the same situation it changes to "1" when I run it from another script (or the command line). The fwait_analyze variable is not overwritten within the dat_numb loop, so I can only assume that there is something going on in the background which I do not fully understand.
@Christian Bretschneider: I'm not sure what the problem is. I'm able to run the code without the problem in R2017b and R2022a, both inside a simple GUI and from the command line.
Can you try creating the waitbar like this:
fwait_analyze = waitbar(0,'1','Name','Analysing Data - Please Wait','CreateCancelBtn','');
ch = get(fwait_analyze,'Children');
set(ch(1),'Callback',{@cb_waitbar_cancel,fwait_analyze});
and define the function cb_waitbar_cancel somewhere in your GUI m-file like this:
function cb_waitbar_cancel(~,~,wb)
setappdata(wb,'canceling',1);
This will guarantee that the setappdata call is happening to the waitbar instead of relying on gcbf.
If that doesn't fix the problem, then at least you can now put a breakpoint in cb_waitbar_cancel and inspect the state of things when the Cancel button callback is executing. For instance, you can see whether getappdata(wb,'canceling') returns 0 before the setappdata(wb,'canceling',1) line is executed, and whether it returns 1 afterward. Or it may be that its callback is not executing at all when you click the Cancel button, which the breakpoint will also tell you, because you'll never hit it.
Another way to try it would be:
fwait_analyze = waitbar(0,'1','Name','Analysing Data - Please Wait','CreateCancelBtn',@cb_waitbar_cancel);
with cb_waitbar_cancel defined as:
function cb_waitbar_cancel(src,~)
hFig = ancestor(src,'figure');
setappdata(hFig,'canceling',1);
@Voss: Thank you. Unfortunately, I'm seeing the same problem with both suggestions (R2023, trial version). It's probably safe to say that the problem is caused by the way I utilize the GUI. I'm going to deactivate the "cancel button" for the time being. In time I need to go back to an archived version of the programme (which didn't exhibit this issue) and compare it line by line. Not something I'm particularly looking forward to, but somehow, I always suspected that it would be necessary.
Thanks anyway. I think this thread can be closed.
I haven't read all comments and code in detail, but this reminds me of situations where you should use drawnow to flush the queue of callbacks. Without it, clicking the cancel button might not do anything until much later.
If this is indeed the case, going through the code line by line will not actually help you find the problem, since after executing a line and pausing, the callback queue is flushed.

Sign in to comment.

Answers (0)

Categories

Find more on App Building in Help Center and File Exchange

Commented:

Rik
on 1 Sep 2023

Community Treasure Hunt

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

Start Hunting!