Problem with "cancel" button (waitbar). User input is ignored.
Show older comments
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
Mario Malic
on 25 Aug 2023
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
Christian Bretschneider
on 29 Aug 2023
Voss
on 29 Aug 2023
@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.
Voss
on 29 Aug 2023
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);
Christian Bretschneider
on 1 Sep 2023
Rik
on 1 Sep 2023
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.
Answers (0)
Categories
Find more on App Building 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!