Matlab waitbar - close all doesn't work - matlab

I have some code which creates a waitbar:
if long_process %user specifies this true/false
h = waitbar(1/4, msg);
end
process(arg1,arg2);
Process is some function which does some plotting. If I do CTRL-C somewhere in process and I get left with a figure window I can just do close all and the figure disappears. However, the waitbar stays. I don't know how to make that thing close with 'close all'.
The reason this is bothering is because when I start debugging I often end up having 20+ waitbars open. 'close all' then comes in handy.

Actually, the close function gives you some more "forceful" options:
close all hidden
close all force
And if for some reason those don't work, one "nuclear" option you have is to delete all figures, including those with hidden handles, as suggested in the close and waitbar documentation:
set(0, 'ShowHiddenHandles', 'on');
delete(get(0, 'Children'));
You may find it easiest to create your own helper function to do this for you (and return the state of 'ShowHiddenHandles' to its default 'off' state) so you don't have as much to type:
function killEmAll
set(0, 'ShowHiddenHandles', 'on');
delete(get(0, 'Children'));
set(0, 'ShowHiddenHandles', 'off');
end
...And even a third option is to try and avoid the problem altogether (if the organization of your code allows it) by using onCleanup objects! If you run the following sample code, the waitbar should be automatically deleted for you when you CTRL-C out of the infinite loop:
function runprocess
h = waitbar(1/4, 'la la la...');
waitObject = onCleanup(#() delete(h));
process();
end
function process
i = 1;
while (i > 0)
i = i + 1;
end
end

Related

How to create a asynchronous waitbar in MATLAB for a parallel external process?

I need to wait for a process to finish with basically unknown duration. I call this process via:
output = system('foo.cmd')
Process foo is blocking any further execution of code. The process takes often about 10 seconds to finish and does not return any status but its output value afterwards. Sometimes it takes a second, sometimes a minute or more. To simulate the progress to the user I would like to implement a waitbar in advance of the excution, somehow like:
function f = my_waitbar()
f = waitbar(0,'Please wait...');
for i=1:10
pause(1)
waitbar(i/10,f,'Executing foo');
end
waitbar(1,f,'Finishing, please wait...'); % should wait now and do nothing
end
Then after foo.cmd finished I would close the bar.
f = my_waitbar() % blocks my code from execution, therefore is pointless
output = system('foo.cmd')
close(f)
But by just calling function f = my_waitbar() in advance, the process would not be triggered parallel. How do I execute my_waitbar() without waiting for it to be finished?
Note that everything after system('foo.cmd') is depending on its execution, therefore further code execution has to wait for it as it does now, so system('foo.cmd &') would not work well for me.
EDIT
Please assume that I have no influence on the content of foo.cmd
It's not a great UX choice to have a percentage-based progress bar which may "complete" long before your process does, or never complete because your process finishes sooner. See this question on UX.stackexchange which discusses the alternatives. In short, a spinner is more conventional.
You can create a custom load spinner fairly easily. This uses an undocumented but simple method to display an animated gif within a figure without having to use code to advance the frames (which would not work for an asynchronous task!).
There are several options for animated gifs already shipped with MATLAB, I've chosen to use this one:
Here is the code and the result (note that in reality the result is animated!)
function hFig = loadspinner()
% Main path for installed MATLAB images (and other files)
fp = fullfile(matlabroot,'toolbox','matlab');
% Path to the image we want, there are other options in this folder...
fp = fullfile(fp, 'sourcecontrol\release\images\spinner.gif');
% Create the figure
hFig = figure('Color', 'w', 'NumberTitle', 'Off', ...
'Resize', 'Off', 'Menubar', 'None');
% Get image size to reduce hard-coding in case we change image
sz = size( imread( fp ) );
% Insert the animated gif into a HTML pane to enable the animation
je = javax.swing.JEditorPane('text/html', ['<html><img src="file:/', fp, '"/></html>']);
[~, hc] = javacomponent(je,[],hFig);
% resize figure and image
hFig.Position(3:4) = [220,sz(2)+35];
set(hc, 'pos', [(220-sz(1))/2-2,6,sz(1)+4,sz(2)+4])
% Add text
annotation( hFig, 'textbox', [0,0.9,1,0], ...
'String', 'Loading, please wait...', ...
'LineStyle','none', ...
'margin', 0, ...
'verticalalignment', 'top', ...
'horizontalalignment', 'center' );
end
You could use this the same as you showed for the waitbar
f = loadspinner();
output = system('foo.cmd')
close(f);
As Wolfie already mentionned, a standard progressbar is not suited to wait for a process with unknown duration (or unknown iterations). In these cases you better use a spinner (gif file), a circular waitbar (good choice on the File Exchange: cProgress), or an indefinite progressbar. This is what I used for this example:
Now how to make it possible. Since I cannot replicate your exact process foo.cmd, I replaced it by the dos command dir. So for the base line example:
tic
command = 'dir' ;
[~,cmdout] = system(command) ;
toc
>> Elapsed time is 1.547987 seconds.
1.5 second is enough to notice, and cmdout does indeed contain the list of files and directories. So I'll assume this is as close as your case than can be.
To be able to monitor the end of the process, I will package the call to dir (or in your case the call to foo.cmd) into a batch file which will:
Check if a file ("MyProcessIsFinished") exist. If yes delete it.
Call the process of interest, redirect the output to a file.
Create an empty file "MyProcessIsFinished"
This allow MATLAB to call the batch file without waiting for the result (using &). You then make MATLAB wait until it detects the file. When detected, you know the process is finished, you can close your waitbar and continue execution of your code. You can then read the file containing the results you used to get in cmdout.
% initialise flag
processFinished = false ;
% start the continuous waitbar
hw = mywaitbar(0.5,'Please wait','Waiting for response ...',true);
% call the process in the batch file, without waiting for result
command = 'mycommand.bat &' ;
system(command) ;
% wait for the process to be finished
while ~processFinished
if exist('MyProcessIsFinished','file')
processFinished = true ;
end
end
close(hw) ; % close the wait bar
% now read your results
cmdout = fileread('outputfile.txt') ;
The file mycommand.bat is now:
#echo off
if exist MyProcessIsFinished del MyProcessIsFinished
dir > outputfile.txt
copy nul MyProcessIsFinished > nul
exit
Don't forget to replace the line dir > outputfile.txt by a call to your process and a redirection to a suitable file name. It could look like:
foo.cmd > ReceivedRequest.json
The continuous waitbar: I picked up mywaitbar.m from the file exchange: mywaitbar. The code is nice but I had to change a couple of things to improve the timer management so if you want a working version there will be a couple of changes:
Line 109: Add 'CloseRequestFcn',#closeRequestFcn to the properties of the new figure.
Line 120: Add 'Name','CircularWaitbarTimer' to the properties of the new timer
Then at the bottom of the file, add the following function:
function closeRequestFcn(hobj,~)
% Delete the timer
t = timerfindall('Name','CircularWaitbarTimer') ;
if strcmpi('on',t.Running)
stop(t) ;
end
delete(t)
delete(hobj)
That will make a more stable waitbar utility and will get rid of the annoying warning/error messages about timers not managed properly.

WindowKeyPressFcn executes after program interruption

I want to detect pressing of the key, when running matlab script in while loop. At the moment, I only want to display success, after pressing of the key. Unfortunately, the message is displayed only after program interruption (CTRL+C) not during program run. Here is the code:
% Init of callback
fig = gcf;
set(fig,'WindowKeyPressFcn',#keyPressCallback);
% keyPressCallback function
function keyPressCallback(source,eventdata)
keyPressed = eventdata.Key;
if strcmpi(keyPressed,'space')
disp('success');
end
end
You need to break the cycle of the script which is running so that Matlab will process other events, in essense your keypress. You can do that by adding a drawnow inside you while loop, the code below should give you enough to incorporate in your own:
fig = figure;
set(fig,'WindowKeyPressFcn',#(hFig,hEvent)fprintf('pressed key %s\n',hFig.CurrentKey) );
drawnow();
while true
if ~ishandle(fig); break; end
drawnow();
end

Duplicating Command window of matlab into customed GUI [duplicate]

i am using GUI to call a terminal command. By using dos(my_command, '-echo') i can get the command output in Matlab's Command Window. Is there anyway to replicate that -echo in a static text in my GUI?
Currently, with my_command, I write the output to a log file, and update the static text's String by this log file after process finishes, but what I want is a live-view like in Command Window: output is displayed line by line in real-time. Thanks.
Update:
#Hoki: another question is: when the console commands are being executed, if I close the GUI then Matlab returns errors unstopable, how can I freeze the whole GUI until the commands are finished?
Thanks to Yair Altman info in this article, I got something to work but it involves hacking into Matlab Java base objects (namely the command window).
It involves attaching a listener to the Matlab command window. Now be careful, save your work often and be prepared to kill Matlab process quite a few times until you get it right ... because every time you have an error in the code you are stuck in a kind of infinite loop (the error/warning is sent to the command window, which triggers your listener, which re-trigger the error etc ...). I had to restart Matlab a good dozen of times just to get the example below to work in a stable way.
That's also the reason why I only attach the listener temporarily. just before sending the dos command and I remove the listener directly after. You can leave the listener permanently or adjust that to your needs but remember the advice from just above. Also consider that the command window can hold a massive amount of character, which you may not want all in your textbox, so you have to manage the text that you get from it (take a subset as in the example), and consider if you want to append or simply refresh the text in the textbox.
The example below seems to be stable as it is, any modification at your own risks ;-)
After request in comment I added 3 functions:
An onCleanup. This is a Matlab functionality to allow last resort action in case something goes wrong (a kind of "catch all" mechanism). Heavily recommended for this kind of program using undocumented functions.
A myCloseRequestFcn which intercept the closing action of the window to remove the listener and avoid error loops.
A scroll_to_bottom function. This one allows to move the text box caret to the end of the text (= to scroll to the bottom in case there is more text than visible space).
Warning: The last functionality could deserve a separate question and again call for undocumented functionality (so the compatibility is never guaranteed). To be able to implement it you need to have the findjobj function available in your Matlab path. If you do not want to download external component, then delete/comment the part of code that uses it and the subfunction scroll_to_bottom (and forget about scrolling the text box, there is no way to do that in pure Matlab). Or you can pick the previous version of the code by looking at the edit history of the post.
function h = gui_MirrorCmdWindow
%% // just to remove the listener in case something goes wrong
closeup = onCleanup(#() cleanup);
%% // create figure and uicontrol
h.f = figure;
h.txtOut = uicontrol(h.f,'Style','edit','Max',30,'Min',0,...
'HorizontalAlignment','left',...
'FontName','FixedWidth',...
'Units','Normalized',...
'Enable','On',...
'Position',[.05 .2 .9 .75]);
h.btnPing = uicontrol(h.f,'Style','Pushbutton',...
'String','Ping',...
'Units','Normalized',...
'Position',[.05 .05 .9 .1],...
'Callback',#btnPing_callback);
guidata(h.f,h)
%// intercept close request function to cleanup before close
set(gcf,'CloseRequestFcn',#myCloseRequestFcn)
%% // Get the handle of the Matlab control window
jDesktop = com.mathworks.mde.desk.MLDesktop.getInstance;
jCmdWin = jDesktop.getClient('Command Window');
jTextArea = jCmdWin.getComponent(0).getViewport.getView;
%% // Get the handle of the jave edit box panel component
jtxtBox = findjobj(h.txtOut) ;
jTxtPane = jtxtBox.getComponent(0).getComponent(0) ;
%// Save these handles
setappdata( h.f , 'jTextArea', jTextArea ) ;
setappdata( h.f , 'jTxtPane', jTxtPane ) ;
function btnPing_callback(hobj,~)
h = guidata(hobj) ;
jTextArea = getappdata( h.f , 'jTextArea' ) ;
my_command = 'ping google.com -n 10' ;
startPos = jTextArea.getCaretPosition ;
set(jTextArea,'CaretUpdateCallback',{#commandWindowMirror,h.f,startPos}) ;
dos( my_command , '-echo' ) ;
pause(1) %// just to make sure we catch the last ECHO before we kill the callback
set(jTextArea,'CaretUpdateCallback',[]) ;
scroll_to_bottom(h.f)
function commandWindowMirror(~,~,hf,startPos)
h = guidata(hf) ;
jTextArea = getappdata( h.f , 'jTextArea' ) ;
%// retrieve the text since the start position
txtLength = jTextArea.getCaretPosition-startPos ;
if txtLength > 0 %// in case a smart bugger pulled a 'clc' between calls
cwText = char(jTextArea.getText(startPos-1,txtLength) ) ;
end
%// display it in the gui textbox
set( h.txtOut, 'String',cwText ) ;
scroll_to_bottom(h.f)
function scroll_to_bottom(hf)
%// place caret at the end of the texbox (=scroll to bottom)
jTxtPane = getappdata( hf , 'jTxtPane' ) ;
jTxtPane.setCaretPosition(jTxtPane.getDocument.getLength)
function myCloseRequestFcn(hobj,~)
cleanup ; %// make sure we remove the listener
delete(hobj) ; %// delete the figure
function cleanup
jDesktop = com.mathworks.mde.desk.MLDesktop.getInstance;
jCmdWin = jDesktop.getClient('Command Window');
jTextArea = jCmdWin.getComponent(0).getViewport.getView;
set(jTextArea,'CaretUpdateCallback',[]) ;
Matlab does not offer a native way to fetch results continuously during the execution of dos, unix and system. Nevertheless there is a possibility to achieve the desired behaviour.
This is the proposed work-around:
Execute your command and pipe the output to a file.
Use the & character to continue execution of the Matlab-code.
Read the contents of this file continuously and update the GUI accordingly.
Introduce a second temporary file indicating the end of the command to stop the update-process.
Here is the code:
% create figure and uicontrol
fh = figure;
txtbox = uicontrol(fh,'Style','edit','Max',30,'Min',0,...
'HorizontalAlignment','left',...
'FontName','FixedWidth',...
'Position',[30 30 450 200]);
% store current path
path = cd;
% delete token to make sure the loop continues as expected
warnstate = warning('off','MATLAB:DELETE:FileNotFound');
delete(fullfile(path,'temp_cmdlog_done'));
warning(warnstate); % restore original warning state
% execute dos-command in background
cmd = 'ping -c 5 192.168.200.1';
dos([cmd,' > temp_cmdlog && echo > temp_cmdlog_done &']);
% refresh text in uicontrol until dos-command is done
while 1
out = fileread('temp_cmdlog');
set(txtbox,'String',out);
if exist(fullfile(path,'temp_cmdlog_done'),'file')
break;
end
pause(0.2); % adjust to suit your needs
end
% delete the temporary files
delete(fullfile(path,'temp_cmdlog'));
delete(fullfile(path,'temp_cmdlog_done'));
% indicate that process finished
set(txtbox,'ForegroundColor',[0,0.5,0]);

Matlab gui WindowButtonMotionFcn crashes when called too often?

I've set WindowButtonMotionFcn to my callback which plots three plots, with the data depending on mouse position. However this seems to be too much for MATLAB to handle, because after moving my mouse around a bit, the GUI stops responding.
I use this code (copied parts from someone):
set(handles.figure1, 'windowbuttonmotionfcn', #hover_Callback);
function hover_Callback(hObject, handles, eventdata)
inside = false;
pos = get(handles.axes1, 'currentpoint');
xlim = get(handles.axes1, 'XLim');
ylim = get(handles.axes1, 'YLim');
if (pos(1,1) > max(xlim(1), 1) && ...
pos(1,1) < xlim(2) && ...
pos(1,2) > ylim(1) && ...
pos(1,2) < ylim(2))
inside = true;
end
if ~inside
return
end
ix = round(pos(1,1));
iy = round(pos(2,2));
axes(handles.axes2); cla; plot(squeeze(t2(ix,iy,:)), squeeze(d2(ix,iy,:)));
axes(handles.axes3); cla; plot(squeeze(t3(ix,iy,:)), squeeze(d3(ix,iy,:)));
axes(handles.axes4); cla; plot(squeeze(t4(ix,iy,:)), squeeze(d4(ix,iy,:)));
This causes my GUI to stop responding, without error codes. If I then quit it and start it again the whole of MATLAB stops responding. Anyone knows what could be happening and how I can fix this? Maybe I'm somehow clogging my memory?
When a callback is called with high frequency, there is the danger that it will be called again before another call has finished executing (i.e. re-entrancy). With WindowButtonMotionFcn, there's a pretty darn good chance that this will happen.
You can prevent callback re-entrancy by inspecting the function call stack (the output of dbstack) for multiple calls to the responsible callback. A very straightforward, but clever implementation of such a check called isMultipleCall is presented in a post on undocumentedmatlab.com. The idea is to count the number of times the callback function name appears on the stack. Take the actual function directly from undocumentedmatlab.com, but it distills to the following:
function flag=isMultipleCall()
s = dbstack();
% s(1) corresponds to isMultipleCall
if numel(s)<=2, flag=false; return; end
% compare all functions on stack to name of caller
count = sum(strcmp(s(2).name,{s(:).name}));
% is caller re-entrant?
if count>1, flag=true; else flag=false; end
The usage of isMultipleCall is very simple. Put run it at the top of the callback (in this case, hover_Callback), and bail out if it indicates that multiple calls are in progress:
function hover_Callback(hObject, eventdata, handles)
if isMultipleCall(); return; end
...
end
This prevents the callback from executing fully again until previous calls have terminated. Only the check will be run, skipping the intensive graphics object operations (i.e. axes, plot, etc.)
An alternative approach is to use a listener for the WindowButtonMotionEvent:
handles.motion = handle.listener(gcf,'WindowButtonMotionEvent',#hover_callback2);
Then in the callback, check the eventdata.CurrentPoint property instead of currentpoint. Check for re-entrancy as above.
If you are NOT using GUIDE and do not have a handles structure managed by guidata, then call the listener something like motionListener and use setappdata to store the listener. For example,
setappdata(hFigure,'mouseMotion',motionListener);
Just use the known handle of any object in the GUI so the listener persists. You could also use UserData instead of setappdata, or any other way of managing GUI data.
As an aside, note that the axes command is rather slow, and can be avoided by passing the axis handle to plot directly:
plot(handles.axes2, squeeze(t2(ix,iy,:)), squeeze(d2(ix,iy,:)));

How to prevent a callback from being interrupted by a figure's close function?

Was wondering how the question in the title can be achieved. I have some callbacks that run from button presses. These callbacks, if interrupted by the figure close, will cause errors because the function seems to run, then gets interrupted by the close function which closes the figure, and then the callback seems to resume after the figure is closed.
If I set the button's 'Interruptible' property to 'on', it prevents other callbacks from interrupting it, but does not seem to work for the figure's close function. Another idea I had was to specify the 'closefunction' in the figuring's 'CloseRequestFcn' callback and then call drawnow to flush the eventqueue before deleting the figure but this did not work.
The last resort for me is to simply set the figure's 'CloseRequestFcn' to '' when running callbacks but this seems tedious. Is there a standard solution to accomplish this?
EDIT:
From matlab's documentation:
Note If the interrupting callback is a DeleteFcn or CreateFcn
callback or a figure's CloseRequest or ResizeFcn callback, it
interrupts an executing callback regardless of the value of that
object's Interruptible property. The interrupting callback starts
execution at the next drawnow, figure, getframe, pause, or waitfor
statement. A figure's WindowButtonDownFcn callback routine, or an
object's ButtonDownFcn or Callback routine are processed according to
the rules described above.
So it appears to be the case that the interruptible property doesn't effect the close function.
EDIT 2:
Ok, so I think I found a problem. It's really bizarre. I actually discovered from the matlab documentation that callbacks are only interruptible if they have the interruptible property set to on AND :
If there is a drawnow, figure, getframe, waitfor, or pause command in the running callback, then MATLAB executes the interrupting callbacks which are already in the queue and returns to finish execution of the current callback.
I don't use any of these functions explicitly, so it turns out most of my callbacks aren't interruptible by the closereqfcn. BUT, it turns out some are, and the reasons why seem very strange. If have a callback with:
`large computation -> imshow -> imshow
large computation -> set -> set -> set -> set
where the set command is setting the axes visible property to off, then no interruption seems to occur if I exit during the callback
Now, if I have:
large computation -> imshow -> set -> imshow -> set
matlab issues an error if I exit during the callback on the second set command. Also, if I have:
large computation -> imshow -> imshow -> set
matlab issues an error if I exit during the callback on the first set command.
large computation -> imshow -> imshow -> imshow
also issues an error on the third imshow if I cancel during the callback.
For some reason it seems that two successive calls to imshow makes my callback interruptible. Is it possible matlab implicitly calls drawnow or does something weird if you use multiple imshows? BTW, my matlab version is R2009a.
I never really trusted that Interruptible flag (or comparable mechanisms)...I immediately admit I have never used it a lot, but that was because when I was experimenting with it for the first time, I noticed that 'Interruptible', 'off' (and friends) seemed to have more exceptions to the rule than vindications of it -- headache material alert!
So, I got in the habit of tackling this sort of problem simply by using flags, and wrapping all callbacks that must really be uninterruptible in a locking/releasing function.
Something like this:
% Define a button
uicontrol(...
'style', 'pushbutton',...
'interruptible', 'off',... % Nice, but doesn't catch DeleteFcn, CreateFcn, ...
% CloseRequestFcn or ResizeFcn
% ...
% further definition of button
% ...
% Put callback in a wrapper:
'callback', #(src,evt) uninterruptibleCallback(#buttonCallback, src,evt)...
);
where uninterruptibleCallback() looks something like this:
function varargout = uninterruptibleCallback(callback, varargin)
% only execute callback when 'idle'
% (you can omit this if you don't want such strict ordering of callbacks)
while ~strcmp( get(mainFigure, 'userData'), 'idle' )
pause(0.01);
% ...or some other action you desire
end
% LOCK
set(mainFigure, 'userData', 'busy');
try
% call the "real" callback
[varargout{:}] = callback(varargin{:});
% UNLOCK
set(mainFigure, 'userData', 'idle');
catch ME
% UNLOCK
set(mainFigure, 'userData', 'idle');
throw(ME);
end
end
Which allows you to use this closeReqFcn() for your figure:
function closeReqFcn(~,~)
% only when the currently running locked callback (if any) has finished
while ~strcmp( get(mainFigure, 'userData'), 'idle' )
pause(0.01);
% ...or some other action you desire
end
% ...
% further clean-up tasks
% ...
% deletion
delete(mainFigure);
end
Theoretically, when you put all callbacks in this sort of schema, it is basically equal to managing your own event queue.
This of course has a few advantages, but many, many drawbacks -- you might want to think this through for a bit. This whole mechanism might be unacceptably slow for your use case, or you might need to define a few more locking functions with far more specific behavior.
In any case, I suspect it's a good place to start off from.
An alternative to #Rody Oldenhuis's solution is to start a timer inside the CloseRequestFcn to close the figure when no uninterruptible code is in progress (which could be indicated by a flag; Closing_Allowed).
function mainFig_CloseRequestFcn(hObject, eventdata, handles)
Time = 3; % Wait time before force killing (in sec)
Kill.tmr = timer('executionMode', 'fixedRate',...
'Period', 1/10,...
'TimerFcn', {#KillingTimer_Callback, handles});
Kill.counts = ceil(Time/Kill.tmr.Period);
setappdata(handles.mainFig,'Kill',Kill);
start(Kill.tmr);
function KillingTimer_Callback(hObject, eventdata, handles)
Kill = getappdata(handles.mainFig,'Kill');
Kill.counts = Kill.counts - 1; % Count down
setappdata(handles.mainFig,'Kill',Kill);
if Kill.counts == 0 || getappdata(handles.mainFig, 'Closing_Allowed')
stop(Kill.tmr);
delete(handles.mainFig);
end
if Kill.counts == 0 means time out, and closes the figure even if an uninterruptible task is in progress, which then would result in the same errors you get sometimes now, but if you know the maximum amount of time you need to finish the uninterruptible jobs, then you can set the Time above properly.
Finally wrap the uninterruptible code by setting the Closing_Allowed flag.
function pushbutton_Callback(hObject, eventdata, handles)
setappdata(handles.mainFig, 'Closing_Allowed', 0); % Closing is not allowed
pause(2);
setappdata(handles.mainFig, 'Closing_Allowed', 1); % Closing is allowed