Stop/Delete Timer Issues While Closing GUI

25 Ansichten (letzte 30 Tage)
Hannes
Hannes am 1 Sep. 2014
Beantwortet: Hannes am 16 Sep. 2014
Hi,
I use a timer to update an axes in a GUI. I want to handle the case in which the user closes the window while the timer is still running, i.e., the axes still beeing updated.
The Problem:
However, every so often the execution time of the TimerFcn is longer than the timers period (depending on the pc's performance). This can cause an error when closing the GUI while the timer is still running.
Error while evaluating TimerFcn for timer 'timer-1'
Bad handle
FYI, I use
T = timerfind;
if ~isempty(T)
stop(T)
delete(T)
end
in the figure's delete function. Apparently, the TimerFcn is still being called after the execution of the figure's delete function. Hence, within my TimerFcn an error occurs during a call to
cla(myaxes),
for cla expects a valid figure handle (though the GUI's figure has just been deleted).
All in all, it seems that the execution time being larger than the timer period is causing this. Of course I could reduce the timer period, but this is not desirable. I figured out a workaround by using a try-catch phrase within the TimerFcn, however it's not a proper solution.
Question:
Is there any way to force the TimerFcn to stop and somehow flush its executin queue/event buffer, regardless of its current state? Any thoughts about solving this issue are very welcome!
Thank you in advance!
Hannes

Akzeptierte Antwort

Image Analyst
Image Analyst am 1 Sep. 2014
Here's my function. I call it in the figMainWindow_CloseRequestFcn() function which gets called when the user tried to close the GUI by any means. To make double sure, I also call in in the callback for a push button I have labeled "Exit", btnExit_Callback(). It looks pretty similar to yours, perhaps a little more robust. I never have any problem with it but I have my timer running at 20 calls per second to monitor a switch on a light booth.
%----------------------------------------------------------------------------
function StopTimer(handles)
try
fprintf('Entering StopTimer...\n');
listOfTimers = timerfindall % List all timers, just for info.
% Get handle to the one timer that we should have.
if isempty(listOfTimers)
% Exit if there is no timer to turn off.
fprintf('There are no timers to turn off. Leaving StopTimer().\n');
return;
end
handleToTimer = getappdata(handles.figMainWindow, 'timerObj');
% Stop that timer.
stop(handleToTimer);
% Delete all timers from memory.
listOfTimers = timerfindall
if ~isempty(listOfTimers)
delete(listOfTimers(:));
end
fprintf('Left StopTimer and turned off all timers.\n');
catch ME
errorMessage = sprintf('Error in StopTimer().\nThe error reported by MATLAB is:\n\n%s', ME.message);
fprintf('%s\n', errorMessage);
WarnUser(errorMessage);
end
return; % from btnStopTimer_Callback
  3 Kommentare
Image Analyst
Image Analyst am 1 Sep. 2014
I don't know. You'll have to call the Mathworks. You say you have some headless, rogue timer running amok even after the timer has been stopped and the timer handle deleted. That's very weird. I have no answer for it.
Hannes
Hannes am 2 Sep. 2014
Bearbeitet: Hannes am 3 Sep. 2014
As I just figured out the probleme you have been right all along!
I was working with the GUI's DeleteFcn and not its CloseReqFcn! So I created a solution that includes another timer. See at below for my solution.

Melden Sie sich an, um zu kommentieren.

Weitere Antworten (4)

Hannes
Hannes am 3 Sep. 2014
Bearbeitet: Hannes am 3 Sep. 2014
As mentioned above, thanks to Image Analyst and Sean de Wolski i figured out a solution to my problem. In addition to my earlier attempt it includes the use of the figure's close request function.
At the beginning of the TimerFcn function I set a flag that the timer is running. If a closereq triggers the CloseReqFcn it validates if the timer is running or not. If so it returns without deleting the figure/GUI, if not it deletes it. At the end of the TimerFcn I set the running flag to false and check if a closereq ist pending. If not, proceed without further ado. If closereq is pending stop/delete the timer and start a second timer that triggers after a certain start delay. Its TimerFcn then calls the closereq function again which finally deletes the figure. This can even be made more robust by doing additional checks and validation using the second timer.
I tested this solution for different computation times.
See attachment for the solution of this problem.
Again, thank you alot for your support! =)
  4 Kommentare
Sean de Wolski
Sean de Wolski am 3 Sep. 2014
Bearbeitet: Sean de Wolski am 3 Sep. 2014
Okay, then wait after stopping
stop(T)
wait(T) % waits for timer to actually stop
delete(T)
delete(fig)
Hannes
Hannes am 3 Sep. 2014
Good idea! Didn't know that. However, error :(.
Error using timer/wait (line 35)
Can't wait with a timer that has an infinite
TasksToExecute.
I tried to set the TasksToExecute property to 1 after i stopped the timer, but then the same old error is echoed.
Error while evaluating TimerFcn for timer 'timer-1'
Invalid object handle

Melden Sie sich an, um zu kommentieren.


Hannes
Hannes am 2 Sep. 2014
Bearbeitet: Hannes am 2 Sep. 2014
I just created a minimal working example that maybe better explains my problem. I attached the mytimer.fig and mytimer.m file.
function varargout = mytimer(varargin)
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, ...
'gui_Singleton', gui_Singleton, ...
'gui_OpeningFcn', @mytimer_OpeningFcn, ...
'gui_OutputFcn', @mytimer_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 mytimer_OpeningFcn(hObject, eventdata, handles, varargin)
% Create global that stores the figure-, axes- and timer-handle.
global gui
gui.figure = hObject;
gui.axes = handles.axes1;
gui.timer = timer('BusyMode', 'drop',...
'ExecutionMode', 'fixedRate',...
'Period', 1/25,...
'TimerFcn', @timer_callback);
handles.output = hObject;
guidata(hObject, handles);
function varargout = mytimer_OutputFcn(hObject, eventdata, handles)
varargout{1} = handles.output;
function pushbutton_start_Callback(hObject, eventdata, handles)
% Update button strings for information.
set(handles.pushbutton_start,'Enable','off')
set(handles.pushbutton_stop,'Enable','on')
% Start the timer.
global gui
start(gui.timer);
function timer_callback(varargin)
% Runs some time consuming calculations.
[x,y] = heavyCalculation();
% Plots data.
global gui
figure(gui.figure);
axes(gui.axes);
cla(gui.axes);
plot(gui.axes,x,y,'Color',[rand rand rand]);
function pushbutton_stop_Callback(hObject, eventdata, handles)
% Stop the timer.
global gui
stop(gui.timer)
% Update button strings for information.
set(handles.pushbutton_start,'Enable','on')
set(handles.pushbutton_stop,'Enable','off')
function figure1_DeleteFcn(hObject, eventdata, handles)
% Delete any timers and display some
% information about that process.
T = timerfind;
if ~isempty(T)
disp('Timers found! Deleting timers ...')
stop(T)
delete(T)
if isempty(timerfind)
disp('All timers deleted!')
else
disp('Still found timers!')
end
else
disp('No timers found!')
end
function [x,y] = heavyCalculation()
N = 50;
data = rand(N,N,N);
tic
for i = 1:size(data,1)
for j = 1:size(data,2)
mean(data(i,j,:));
end
end
x = rand(1,N);
y = rand(1,N);
% Displays the default and required fps.
% % fprintf('Timer period: 0.0400 seconds per frame <=> 25.0000 fps\n')
% % fprintf('Required: %1.4f seconds per frame <=> %2.4f fps\n',toc,1/toc)
On my system it causes the following message and error.
Timers found! Deleting timers ...
Still found timers!
Error while evaluating TimerFcn for timer 'timer-1'
Invalid object handle
By setting N in heavyCalculation() from now 50 to , e.g., 10, it decreases the required computation time alot and the required fps are much larger than 25. This way no error occurs. So my assumption is, that the computation time being to long causes this error.

Sean de Wolski
Sean de Wolski am 2 Sep. 2014
Another thing you can do is inside of the timerfcn, validate that it won't error by checking the whether the axes (or whatever else) is still valid. For example:
function TimerEx3
ax = axes;
T = timer('Period',1,... %period
'ExecutionMode','fixedRate',... %{singleShot,fixedRate,fixedSpacing,fixedDelay}
'BusyMode','drop',... %{drop, error, queue}
'TasksToExecute',inf,...
'StartDelay',0,...
'TimerFcn',@(src,evt)timerfcn(src,evt,ax),...
'StartFcn',[],...
'StopFcn',[],...
'ErrorFcn',[]);
start(T);
end
function timerfcn(src,evt,ax)
drawnow
% Check if the axes exists, if it doesn't, kill the timer
if ~ishandle(ax)
stop(src)
delete(src)
else
% Do whatever
plot(rand(1,10))
end
end
  3 Kommentare
Sean de Wolski
Sean de Wolski am 2 Sep. 2014
Well if you're plotting to the axes, just checking the axes will assert the existence of the parent figure. If you're updating the line, checking the line will assert the existence of the axes and figure. Basically, the lower you can check on the graphics hierarchy, the less you have to do.
Image Analyst
Image Analyst am 2 Sep. 2014
I think if the axes is gone, everything else will be gone too because you're shutting down or have already shutdown, so you should not have to check for existence of any other controls.

Melden Sie sich an, um zu kommentieren.


Hannes
Hannes am 16 Sep. 2014
Conclusion:
Running TimerFcns can be interrupted, e.g., by the GUIs CloseRequestFcn or several other callback functions. MATLAB continous to finish execution of the TimerFcn after the interrupting routine is finished.
Such being the case, onne has to check if the interrupting routine changed/deleted variables/objects the TimerFcn requires. For example, in the case posted above during execution of the TimerFcn a call to a deleted graphic object (due to the figure being closed) caused an error. To negotiate this obstacle, before I delete the figure, I check whether the TimerFcn is running or not and delay closing the figure accordingly.
Many thanks to Image Analyst and Sean de Wolski for their help and suggestions :-).

Kategorien

Mehr zu Interactive Control and Callbacks finden Sie in Help Center und File Exchange

Community Treasure Hunt

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

Start Hunting!

Translated by