Stop/Delete Timer Issues While Closing GUI
8 次查看(过去 30 天)
显示 更早的评论
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
0 个评论
采纳的回答
Image Analyst
2014-9-1
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 个评论
Image Analyst
2014-9-1
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.
更多回答(5 个)
Hannes
2014-9-3
编辑:Hannes
2014-9-3
4 个评论
Sean de Wolski
2014-9-3
编辑:Sean de Wolski
2014-9-3
Okay, then wait after stopping
stop(T)
wait(T) % waits for timer to actually stop
delete(T)
delete(fig)
Sean de Wolski
2014-9-2
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 个评论
Sean de Wolski
2014-9-2
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
2014-9-2
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.
Jean-Baptiste
2024-7-16
编辑:Jean-Baptiste
2024-7-16
This is a bit old but I was facing the same issue.
The main problem is that the close figure callback needs to exit before the timer callback can resume (and consequently the stop function to be triggered).
One proper implementation of such a case is to have the close figure callback checking if the timer is running. If yes, it requests stop function timer to recall the close figure callback by setting a flag in UserData (tm.UserData.req_close).
In the first example, the timer is running. In the second, the time is not running.
function example
% This example shows how to stop a timer from a callback while the timer is running.
fprintf('--------------------\nFigure with timer.\n');
d.hfig = figure('CloseRequestFcn', @cb_close, 'Name', 'Timer is running.');
d.tm = timer('ExecutionMode', 'fixedDelay', 'Period', 4, 'BusyMode', 'drop', ...
'StartFcn', @tm_start, 'StopFcn', @tm_stop, 'TimerFcn', @tm_fun);
d.tm.UserData.hfig = d.hfig;
guidata(d.hfig, d);
start(d.tm);
waitfor(d.hfig);
% Try without the timer. Note that the timer must still be a valid object even if not running.
fprintf('--------------------\nFigure without timer.\n');
d.hfig = figure('CloseRequestFcn', @cb_close, 'Name', 'Timer is not running.');
d.tm = timer('ExecutionMode', 'fixedDelay', 'Period', 4, 'BusyMode', 'drop', ...
'StartFcn', @tm_start, 'StopFcn', @tm_stop, 'TimerFcn', @tm_fun);
d.tm.UserData.hfig = d.hfig;
guidata(d.hfig, d);
waitfor(d.hfig);
end
%% Timer functions.
function tm_start(tm, ~)
fprintf('Timer starts.\n');
tm.UserData.req_close = false;
end
function tm_stop(tm, ~)
fprintf('Timer stops.\n');
if tm.UserData.req_close
fprintf('Recall cb_close.\n');
cb_close(tm.UserData.hfig);
% NOTE: from here to the end of the function, tm cannot be used.
end
end
function tm_fun(~, ~)
% NOTE: this function will never be interrupted by stopping the timer.
fprintf('Function running...\n');
pause(2); % Just do something.
fprintf('Function ended.\n');
end
%% Callbacks.
function cb_close(hobj, ~)
d = guidata(hobj);
fprintf('Closing called.\n');
if d.tm.Running == "on"
% Do not close the figure here.
d.tm.UserData.req_close = true;
stop(d.tm); % Will recall cb_close(hobj);
else
% Now timer and figure can be deleted.
delete(d.tm);
delete(d.hfig);
end
fprintf('Closing ended.\n');
end
Here is an example of output
--------------------
Figure with timer.
Timer starts.
Function running...
Function ended.
Function running...
Function ended.
Function running...
Closing called. % User click on the top left cross.
Closing ended. % Here the close figure callback ends.
Function ended. % The timer function ends
Timer stops. % Then the timer stop is called.
Recall cb_close. % Triggering another call of the close figure callback.
Closing called.
Closing ended.
--------------------
Figure without timer.
Closing called.
Closing ended.
0 个评论
另请参阅
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!