Delete a timer object in it's callback
4 views (last 30 days)
Show older comments
I have short timer callbacks to change a color from a button press or other action back to it's original color. This gives a nice flash of color when that action happens. Since the names given to a timer when it is declared don't really exist e.g."timer-1" and you don't get to know which one it is anyway, I tagged them like this:
Example: Set color then start timer
app.LickRight.Color='green';
tR = timer;
tR.Tag = "tR"; % Tag it with it's own name
tR.StartDelay = 0.1;
tR.TimerFcn = @(~,~)app.RightBlack;
start(tR);
The callback looks like this:
function RightBlack(app,~)
app.LickRight.Color='black';
stop(timerfind('Tag','tR'));
delete(timerfind('Tag','tR'));
end
break at the start of the callback after color change:
1042 stop(timerfind('Tag','tR'));
K>> timerfind('Tag','tR')
ans =
Timer Object: timer-2
Timer Settings
ExecutionMode: singleShot
Period: 1
BusyMode: drop
Running: on
Callbacks
TimerFcn: @(~,~)app.RightBlack
ErrorFcn: ''
StartFcn: ''
StopFcn: ''
First question: Since it's a singleShot and I timed out into the callback why is it still Running On
OK, I can handle it with
stop(timerfind('Tag','tR'));
Step into that and check
K>> timerfind('Tag','tR')
ans =
Timer Object: timer-2
Timer Settings
ExecutionMode: singleShot
Period: 1
BusyMode: drop
Running: off
Callbacks
TimerFcn: @(~,~)app.RightBlack
ErrorFcn: ''
StartFcn: ''
StopFcn: ''
OK, that worked, now it's off at least. Next line executed:
delete(timerfind('Tag','tR'));
Check again for this one:
K>> timerfind('Tag','tR')
ans =
Empty timer object: 0-by-0
That's interesting, not sure what it means. Let's check all timer objects
K>> timerfind
ans =
Timer Object: timer-2
Timer Settings
ExecutionMode: singleShot
Period: 1
BusyMode: drop
Running: off
Callbacks
TimerFcn: @(~,~)app.RightBlack
ErrorFcn: ''
StartFcn: ''
StopFcn: ''
Wait what!? Is it there or not:
Let's delete everything for now (Can't do this in the real program, multiple timers could be running at once)
K>> delete(timerfind)
K>> timerfind
ans =
[]
Yeah, that's what I'm looking for. Why didn't I get it the first time?
Here's what's weird: When I try it again it does delete and I don't get what's above. How did that happen the first time? (retorical question)
Is this clear simple way to find a timer so you can delete it in the callback? Is it OK to put lessons learned here inMatlabCentral for others to find?
I'm asking any way because the HELP for this kind of thing is archaic (GUIDE) and a very long solution from IDK how long ago whith all kinds of handle manipulation. Let's show how timer cleanup can be done easily, because if you don't delete them after they run they pile up eating memory, even outlasting stopping and rerunning the program, because they are separate process threads.
Oh, one more thing. Good practice when using timers in an App Designed program to do this when app closes in the built in function?
% Close request function: MouseOdor
function MouseOdorCloseRequest(app, event)
fclose('all'); % closes all open files. This probably happens anyway?
% Clear all timers
stop(timerfindall);
delete(timerfindall);
delete(app);
end
Anyone else notice that you can't add text after a code section unless you leave some blank lines below where you are typing?
2 Comments
Les Beckham
on 3 Oct 2024
I can't help with your timer issues, but I can help with your comment/question about adding text after a code section in Answers. When you are done typing in a code section, either press Alt-Enter or click the far left icon in the toolbar
Walter Roberson
on 3 Oct 2024
delete(timerfind('Tag','tR'));
Why are you not permitting the default parameters to pass into the timer callback? The first of the default parameters is a reference to the timer that is being referred to, which would save you a lot of timer finding
Accepted Answer
dpb
on 3 Oct 2024
Moved: dpb
on 3 Oct 2024
"Since the names given to a timer when it is declared don't really exist e.g."timer-1..."
Au contraire, good buddy...
tR=timer('Name','timerRight')
timerfind('Name','timerRight')
delete(tR)
timerfind('Name','timerRight')
But, there's no reason to do such things as
delete(timerfind(...))
You will know which timer it is by the variable to which you assigned it when it was created; simply use it as illustrated above to control all its properties/behavior.
The single-shot time will turn itself off when it fires and the callback function completes. Inside the debugger, however, you may have interrupted it and also the state of events after the single step and delete may not be updated immediately.
It's not clear specifically, what issue you are having that you are asking about -- from the question title, if the real question is can you delete the object itself in the StopFcn callback, the documentation specifically says you can...
You can use StopFcn to define cleanup actions, such as deleting the timer object from memory.
If you specify this property by using a function handle, when MATLAB executes the callback,
it passes the timer object and an event structure to the callback function. The event structure
contains the type of event in the Type field and the time of the event in the Data field.
In a situation such as you've described, bowever, it would seem a big waste to do that and have to recreate a new one unless it really is only going to ever be called on the one time...other than that, it would seem to make sense to keep them hanging around and simply execute the start method/function again...
start(tR)
for the specific button. You could also have either an array or use the same timer for the purpose rather than having one for every button.
3 Comments
dpb
on 3 Oct 2024
Edited: dpb
on 3 Oct 2024
"Moved" just means I started out to write a comment and then decided it was worthy of being an answer after submitting it...it makes no difference as to visibility or in any other way.
As far as the handle, given the organization of how an AppDesigner app is coded, making the objects you need more than one place as shared data elements is the expected and most effective way to program. It is far better to be able to reference the given timer directly by variable name in that manner than having to look it up everytime. While your machine may be faster than blazes; the overhead associated with the gui is still observational and there's no sense in using up CPU cycles that aren't really necessary at all.
And, for the app, the timer is NOT temporary--it may only be active occasionally but the next time that event occurs it's going to take creating a new one for the action--and that takes overhead that isn't needed if you instead just restart the same onee. I would only consider something temporary if it only ever executes on startup, for example, and never again is there any way for it to ever occur again.
If there are multiple different actions, then there may need to be different timers, but if it is a similar action as your initial description of just toggling a gui element color, then there is the possiblity of using the same callback; it could even have stored a case to select different color/time, etc., based on the control that called it rather than duplicating the code for every similar object.
Bruno Luong
on 3 Oct 2024
Reuse the same timer is tricky too do it properly IMO. What happens if the first one is not finish yet? Do you have to stop it then restart it? Are they stack in the queue? What happens if there is an error, is StopFcn is invoked so you can be sure it get invoked?
I don't think the document describe those fine behavior precise enough, and I don't have any desire to spend my time to figure that out. Computer IMO now a day is fast enough. You cannot imagine have many tasks is runing by various things at the same time under window. A little timing a really negligible IMO.
More Answers (1)
Bruno Luong
on 3 Oct 2024
I don't know, but I have programmed the same toys, my worlflow is like this
close all;
fig = figure;
ax = axes('Parent', fig);
text(ax, 0.5, 0.5, 'Click with your mouse', 'HorizontalAlignment','center')
set(fig, 'WindowButtonDownFcn', @(varargin) Blinking(ax))
%%
function Blinking(ax)
% Callback when the user use mouse right-click on the figure
% ZOOM and PAN must turned off
mouse = get(ax,'CurrentPoint');
x = mouse(1,1);
y = mouse(1,2);
% Make the selection point blinking
try %#ok
delete(findobj(ax,'Tag','BlinkingSquare'));
end
try %#ok
t = timerfind ('Tag','BlinkingTimer');
stop(t);
delete(t);
end
hold(ax,'on');
hr = plot(ax,x,y,'rs',...
'MarkerSize', 20, 'MarkerFaceColor', 'r', ...
'Tag','BlinkingSquare');
xlim(ax, [0 1])
ylim(ax, [0 1])
tblink = 0.25;
nblink = 15;
t = timer(...
'Name', 'BlinkingTimer',...
'ExecutionMode', 'fixedSpacing',...
'Period', tblink, ...
'StartDelay', tblink, ...
'TasksToExecute', nblink, ...
'TimerFcn', @(varargin) BlinkingToggle(hr), ...
'ErrorFcn', @(varargin) delete(hr), ...
'StopFcn', @(varargin) delete(hr), ...
'Tag', 'BlinkingTimer');
start(t);
end % Blinking
%% Make the red square toogle between visible on and off
function BlinkingToggle(hr)
if strcmp(get(hr,'Visible'),'on')
set(hr,'Visible','off');
else
set(hr,'Visible','on');
end
end
2 Comments
Bruno Luong
on 7 Oct 2024
Edited: Bruno Luong
on 7 Oct 2024
I can't clearly see why timer must be specifically designed for AppDesigner, but I may be wrong.
See Also
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!