Stop Matlab timer from within its callback (after outside input/event) - matlab

I am running a long data preload within a timer callback, and I would like to be able to stop the callback halfway through with an outside input (for instance, the click of a GUI button).
The stop() function will stop the timer calls, but not the callback function itself.
Here is a simple example:
timerh = timer('TimerFcn' , #TimerCallback,'StartDelay' , 1, 'ExecutionMode' , 'singleShot');
NeedStopping = false;
start(timerh)
disp('Running')
pause(1)
disp('Trying to stop')
NeedStopping = true;
function TimerCallback(obj, event)
% Background data loading in here code in here; in this example,
% the callback simply displays numbers from 1 to 100
for k = 1 : 100
drawnow(); % Should allow Matlab to do other stuff
NeedStopping = evalin('base' , 'NeedStopping');
if NeedStopping
disp('Should stop now')
return
end
disp(k)
pause(0.1)
end
end
I expect this script to display numbers between 1 and (approximately) ten, but the timer callback does not stop until 100.
Strangely, the code reaches the line just before before the pause(1) and correctly prints 'Running', but then it stops there and waits for the timer to finish.
Even more perplexing, if I change the 1 second pause to 0.9 seconds, the timer stops immediately with this output:
Running
Trying to stop
Should stop now
I am aware that Matlab is mostly single-threaded, but I thought the drawnow() function should allow it to process other stuff.
Edit: Specific use behind my question:
I have a GUI with a "next" button that loads several images and shows them all side by side. The images are large so loading takes time; therefore, while the user looks at the pictures, I want to preload the next set. This can be done in the background with a timer, and it works.
However, if the user clicks "next" before the preloading has finished, I need to stop it, show the current images, and launch the preloading for the next step. Hence, the timer needs to stop during callback execution.

This is a demo of how to set up an interruptible callback. The way your example is set up I didn't see the need for an actual timer so I made it as a standard button callback.
note: If you are dead set on using it for a timer you can use exactly the same solution, just assign the startProcess callback to the timer instead of the gui button.
function h = interuptible_callback_demo
% generate basic gui with 2 buttons
h = create_gui ;
guidata( h.fig , h )
% create application data which will be used to interrupt the process
setappdata( h.fig , 'keepRunning' , true )
end
function startProcess(hobj,~)
h = guidata( hobj ) ;
% set the 'keepRunning' flag
setappdata( h.fig , 'keepRunning' , true )
% toggle the button states
h.btnStart.Enable = 'off' ;
h.btnStop.Enable = 'on' ;
nGrainOfSand = 1e6 ;
for k=1:nGrainOfSand
% first check if we have to keep running
keepRunning = getappdata( h.fig , 'keepRunning' ) ;
if keepRunning
% This is where you do your lenghty stuff
% we'll count grains of sand for this demo ...
h.lbl.String = sprintf('Counting grains of sands: %d/%d',k,nGrainOfSand) ;
pause(0.1) ;
else
% tidy up then bail out (=stop the callback)
h.lbl.String = sprintf('Counting interrupted at: %d/%d',k,nGrainOfSand) ;
% toggle the button states
h.btnStart.Enable = 'on' ;
h.btnStop.Enable = 'off' ;
return
end
end
end
function stopProcess(hobj,~)
h = guidata( hobj ) ;
% modify the 'keepRunning' flag
setappdata( h.fig , 'keepRunning' , false )
end
function h = create_gui
h.fig = figure('units','pixel','Position',[200 200 350 200]) ;
h.btnStart = uicontrol('style','pushbutton','string','Start process',...
'units','pixel','Position',[50 100 100 50],...
'Callback',#startProcess) ;
h.btnStop = uicontrol('style','pushbutton','string','Stop process',...
'units','pixel','Position',[200 100 100 50],...
'Callback',#stopProcess,'enable','off') ;
h.lbl = uicontrol('style','text','string','','units','pixel','Position',[50 20 200 50]) ;
end
To see it in action:

Related

MATLAB - AppDesigner: Interrupt a loop with GUI

I have created a GUI which computes a trajectory based on an external .m file.
When the user press the 'Calculate' button, the external .m function file gets called via the callback function of the button:
% calculateBtn button pushed function
function calculate(app)
numSteps = app.stepSlider.Value;
app.omega = app.omegaSpin.Value;
app.phid = app.phi.Value;
app.x0 = app.x0Spin.Value;
app.y0 = app.y0Spin.Value;
app.u0 = app.u0Spin.Value;
app.v0 = app.v0Spin.Value;
set(app.calculateBtn, 'Enable', 'off')
set(app.showBtn, 'Enable', 'off')
[app.Xc, app.Xi, app.C, T, f]=coriolis_traj(app.x0, app.y0, app.u0, app.v0, app.phid, numSteps);
app.fEdit.Value = num2str(f);
app.tEdit.Value = num2str(T);
set(app.calculateBtn, 'Enable', 'on')
if length(app.Xc)>1
set(app.showBtn, 'Enable', 'on')
else
set(app.showBtn, 'Enable', 'off')
end
end
The external file consists of the main loop of the computations.
while 1
% Counters
i = i + 1;
t = t + Dt;
theta = theta + Omega * Dt;
% Parcel's position
% on the inertial frame
x1 = x0 + Dt*u0;
y1 = y0 + Dt*v0;
% Parcel's position translated to the
% rotating frame
xc1 = x1*cos(theta)+y1*sin(theta);
yc1 = x1*sin(theta)+y1*cos(theta);
x(i) = x1 ; y(i) = y1;
xc(i) = xc1 ; yc(i) = yc1;
x0 = x1 ; y0 = y1;
[in] = inpolygon(xc,yc,xv,yv);
if ~in(i) > 0
break;
end
end
I want to stop the computation and clear the computed arrays when the user changes any of the values in 'Controls' panel, or when the button 'Break' is pushed.
How could I code this?
The best solution I can figure out is to bring your while loop inside your GUI callback. The inner code of your while loop can be kept on a separate, external file, but bringing in the loop will give you full control over it and will make it easier to interrupt. The only constraint is that it must be make less "tight"... it must contain a small pause (better if followed by a drawnow() call) so that the main GUI thread can have the time to process the application messages.
And here is the code of your callbacks:
% Computation Callback
function Button1_Callback(obj,evd,handles)
obj.Enable = 'off'; % disable this button
handles.Button2.Enable = 'on'; % enable the interruption button
handles.stop = false; % the control variable for interruption
while (true)
% call your external function for running a computational cycle
res = myExternalFunction(...);
% refresh the application handles
handles = guidata(obj);
% interrupt the loop if the variable has changed
if (handles.stop)
break;
end
% this allows the loop to be interrupted
pause(0.01);
drawnow();
end
obj.Enable = 'on';
end
% Interruption Callback
function Button2_Callback(obj,evd,handles)
obj.Enable = 'off'; % disable this button
handles = guidata(obj);
handles.stop = true;
end
There is no way in MATLAB to interrupt a function by another function, e.g. say programmatically injecting a CTRL-C into another running function, without modifying the to-be-interrupted function.
The closest you can get is by modifying the simulator code to regularly perform a callback. This is how I integrated by simulation code into a GUI. IMO it is a clean solution and also works with MEX files.
Think of it as a progress callback for your simulator code.
It could be regularly (e.g. every second, or at completion of the i-th step) called by the simulator with some percentage parameter to indicate the degree of completion.
If you modify the simulator code to stop simulating in case the callback returns false, you achieve what you want. At the same time this is minimum invasive in your simulator code. Supply a dummy callback and it will run stand alone.
GUI pseudocode:
function button_cancel_Callback(hObject, eventdata, handles)
global cancel_pressed;
cancel_pressed = true;
function dostop = callback( progress, handles )
<show progress>( handles.<XXX>, progress );
global cancel_pressed;
if cancel_pressed
dostop = true;
else
dostop = false;
end
function button_run_simulation_Callback(hObject, eventdata, handles)
global cancel_pressed;
cancel_pressed = false;
<simulator function>( ..., #callback, handles )
SIMULATOR pseudocode:
function <simulator function>( ..., callback, callback_param )
while ... % main loop
if ~isempty(callback) && ~callback( progress, callback_param )
error("canceled-by-user") % could also be something more elaborate
end
return "simulation completed"

How can I check mouse events as a background process in Matlab?

I am using Matlab to develop an application which performs several mathematical operations, whose parameters can be changed when the mouse is clicked, as in the example below.
while time<endtime
calculate_manythings;
if ~mod(time,checkmouse)
mouseinput_timeout(timemouse, gca);
change_calculation_parameters;
end
time=time+1;
end
At the moment, I am pausing the operations periodically to check for mouse events, but this is slow and unpractical. How can I monitor these continually and run the code at the same time? Could I make the mouse event checks a background process using parfeval, for example?
Many thanks,
Marta
you can use callback functions. here I used 'ButtonDownFcn':
timeinterval = 1; % seconds between mouse clicks
% generate axes with callback function
h = plot(rand(1,2),'LineWidth',6);
set(gca,'ButtonDownFcn',#callback);
% reset Tag and time
h.Tag = '';
tic;
while true
drawnow;
if strcmp(h.Tag,'Pressed') % if pressed
t = toc; % check time passed
if t >= timeinterval
% change parameters
disp('Pressed');
h.Color = rand(1,3);
% reset timer
tic;
end
% reset Tag
h.Tag = '';
end
end
and the callback function is:
function callback(src,~)
src.Children(1).Tag = 'Pressed';
end

Real-time update of values inside a call_back function[the values are from external function(of another .m file)]

I have an external function say "external_func" (seperate .m file)
Inside this function a while loop is called, and this while loop update a variabl named "update_prog"
Now I will pass this value into the GUIDE using
assignin('base', 'update_prog', update_prog); % passing to workspace
I am making this
"update_prog" as global variable and calling it into GUIDE .m file
function pb1_Callback(hObject, eventdata, handles)
global update_prog
% hObject handle to pb1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% else
% set(handles.pb1,'enable','on');
% end
% update_prog first value prints, but it wont updates as the loop in external_func goes on.
drawnow;
set(handles.slider1,'Value',update_prog)
external_func;
so here in the GUIDE .m file I can get the value
"update_prog" but it wont keep up with the while loop. I used "drawnow" but its of no use.
How can I refine this value "update_prog" as the while loop in the "external_func" goes through multiple iterations. [Note: The updated values are there in the callback function of GUIDE, but unless there is a callback the callback function wont update the "update_prog"], so how can I acheive this real-time update inside a call_back function.
[Note: passing the variables through function input is not possible here in my case, so I am looking for alternatives]
Edit1: please consider this link, which has an exampleWhich may clarify you what I am trying to acheive
What I am doing here is
Passing the variable(which is being updated in the while loop of the externel function) into GUI.
I will use this variable to show the progress on the progress bar(Slider).
What is the problem?
1. The variable inside the GUI callback(Consdier I will press a push button and then it will call the function with while loop) will put the updated values into the set(handles.slider,'Value',variable)
By doing this I cant move the slider.
Why?
Callback updates the variable only when I press the push button, next all the updates to the variable will not be updated, so progress bar/slider wont move.
I wouldn't recommend to pass your variable in 3 steps with an intermediate workspace (external->base workspace->GUI). I would rather recommend to pass your variable directly (external->GUI).
Each Matlab figure offers a space to store variables (Application Data) of any type. I would suggest reading the article Share Data Among Callbacks and read the documentation for the 3 functions:
guidata
setappdata
getappdata
This way will offer you much more control over the scope of your variables and you won't need any global declaration.
Below is an example of a simple gui. The gui declare the variable in it's user space (with setappdata), then uses a timer to periodically read this variable (with getappdata).
The external function do whatever you want it to do (just a random number in the example), then to update the variable you use the same setappdata. The only thing you need for that is the handle of the main GUI figure, so in the example I give it as input of the external function.
The GUI also has two buttons to start and stop the update.
The code for the main example GUI 'theGui.m' is :
function h = theGui
%// basic GUI with 2 buttons and 1 slider
h.fig = figure('Position',[433 434 500 100],'Menubar','none','CloseRequestFcn',#my_closefcn) ;
h.sld = uicontrol('Style','Slider','Position',[20 20 460 20]) ;
h.btnStart = uicontrol('Style','pushbutton','String','Start updating','Callback',#btnStart_callback,'Position',[20 50 200 30]);
h.btnStop = uicontrol('Style','pushbutton','String','Stop updating','Callback',#btnStop_callback,'Position',[280 50 200 30],'Max',1,'Min',0);
%// Define the timer
h.t = timer ;
h.t.Period = 0.1 ; %// 0.1s refresh interval
h.t.TimerFcn = {#timer_callback,h.fig} ;
h.t.ExecutionMode = 'fixedSpacing' ;
%// initialise the variable to update in the GUI appdata
update_prog = 0 ;
setappdata( h.fig , 'update_prog' , update_prog ) ;
%// save handles
guidata( h.fig , h );
function btnStart_callback(hobj,~)
h = guidata( hobj ) ; %// retrieve handles
if strcmp('off',h.t.Running) %// Start timer (only if not already running)
start(h.t)
end
function btnStop_callback(hobj,~)
h = guidata( hobj ) ; %// retrieve handles
stop(h.t) %// Stop timer
function timer_callback(~,~,hfig)
update_prog = getappdata( hfig , 'update_prog' ) ; %// retrieve the 'update_prog' variable value
h = guidata( hfig ) ; %// retrieve handles
set(h.sld , 'Value' , update_prog) ; %// update the slider object with the retrieved value
function my_closefcn(hobj,~)
%// this function is only to clean up when the GUI will be closed.
%// It is recommended to delete the timer manually
h = guidata( hobj ) ; %// retrieve handles
stop(h.t) %// Stop timer (in case it is still running)
delete(h.t) ; %// delete the timer
delete(h.fig) ; %// destroy the figure
And the code for external_func.m
function external_func( guiMainFigureHandle )
%// This function will only generate random numbers and push them into the
%// variable 'update_prog' contained in the GUI appdata.
%// This is why this function NEEDS the handle of the gui to be able to
%// access the Application Data space of the gui.
for k = 1:100
randomValue = rand(1) ; %// generate a random value
hfig = ancestor( guiMainFigureHandle , 'figure' ) ; %// make sure the handle provided is the top level figure
setappdata( hfig , 'update_prog' , randomValue) ; %// update the variable value
pause(0.1) ;
end
Edit:
I place this in edit instead of changing the code above because I don't recommend messing with the root object if you don't need to. But in your case it can be a way round your problem.
If your external function doesn't have access to the GUI, it can always update a part of memory which is available for all the programs running in a given Matlab session, namely the root object. The handle for it is reserved and is the same for any program: 0 (although since v2014b there is another way to invoke it : groot, it is still always the same handle for all Matlab).
So in the example above, in theGui.m, use instead:
setappdata( 0 , 'update_prog' , update_prog ) ;
in the main routine, then in the subfunction function timer_callback(~,~,hfig), use:
update_prog = getappdata( 0 , 'update_prog' ) ; %// retrieve the 'update_prog' variable
And your function external_func() doesn't need any extra argument, the update only needs one line:
setappdata( 0 , 'update_prog' , update_prog) ; %// update the variable value
I "suspect" that your update_prog variable in the base workspace is not a global (you must define it to be global in every workspace that you want to use it).
Since your using globals (there are many better ways to do this - but thats not your question) - why don't you simply define the update_prog variable to be global in your external_func function (replace the assign call).
edit put a drawnow in your external_func function. That way when you click on the button it will update.
edit 3
I think I know what you want to do, try this example and see if it does what you want - updated to show how you find the slider object in your code and update inside your loop:
function mygui
% create a figure
f = figure;
% create a uicontrol slider - note that I give it a tag.
uicontrol ( 'style', 'slider', 'Position', [0 200 200 40], 'tag', 'MYSLIDER', 'backgroundcolor', 'white', 'parent', f );
% create a push button which we can press to update
uicontrol ( 'string', 'Press 2 start', 'callback', #(a,b)myLoop(), 'Position', [0 0 200 50] )
end
% This replicates your "external_func" function.
function myLoop()
% since you cant pass in any var -> you need to find the slider object
% you can do this by using findobj and search for the tag of the item
uic = findobj ( 0, 'tag', 'MYSLIDER' );
% find the figure handle (only needed for this demo)
f = ancestor ( uic, 'figure' );
% initialise the value which will be used to update the slider
count = 0;
% create your loop
while ishandle(f)
% incrememt the count variable -> this will end up on the slider value
count = count + 1e-5;
% reset count if > 1 -> so the slider cant go out of range.
if count >= 1
count = 0;
end
set ( uic, 'Value', count );
% initiate a drawnow -> this allows matlab to process GUI events
drawnow();
end
end
The downside of this is you insert a drawnow in your loop -> which could slow it down somewhat.
If this doesn't fix your problem you need to explain better what you want to do... (in my view)

How to update date and time in matlab gui

function demo1()
H.f = figure('Name','DEMO1');
set(H.f,'Units','Pixels','Position',get(0,'ScreenSize'));% adjust figure size as per the screen size
H.pb1 = uicontrol('style','push',...
'units','pixels',...
'position',[400 800 280 30],...
'fontsize',14,...
'string', datestr(now)); % datestr(now) is used to get current date and time
end
how i can get the real time clock in gui
This is not really an easy task to perform and you may want to think about your design. This could be wrapped in a class, but not necessarily. In case you do not want to do this you may be able to modify the underlying Java objects, but that seems to be overworking this. I have instead structured this in a more C-style manner with placing all data in a struct and writing functions taking the struct as an argument. However, since matlab does not support passing memory locations you need to return the struct after modifying it.
I have chosen to use a timer object for this. You need to store the timer object somewhere since it needs to be deleted when you are not using it anymore. Further, I have added some code for using a start function and stop function as well. For the timer object. This for seeing that the object actually gets finished during development phase. This is not needed for the final project. Further, you may want to handle the case where the window is closed. This will cause the current implementation to crash since the timer is independent of the figure and does not stop when the figure is closed. You probably want to call stop_timer on closing the figure. Anyway here is the code:
function test()
h.f = figure('Name','DEMO1');
set(h.f,'Units','Pixels','Position',get(0,'ScreenSize'));% adjust figure size as per the screen size
h.pb1 = uicontrol('style','push',...
'units','pixels',...
'position',[400 800 280 30],...
'fontsize',14,...
'string', datestr(now)); % datestr(now) is used to get current date and time
h = start_clock(h);
pause on;
pause(15);
pause off;
h = stop_clock(h);
end
function obj = start_clock(obj)
%TasksToExecute calls the timer object N times
t = timer('StartDelay', 0, 'Period', 1,... % 'TasksToExecute', inf, ...
'ExecutionMode', 'fixedRate');
t.StartFcn = {#my_callback_fcn, 'My start message'};
t.StopFcn = { #my_callback_fcn, 'My stop message'};
t.TimerFcn = {#set_time, obj};
obj.t = t;
start(obj.t);
end
function obj = stop_clock(obj)
stop(obj.t);
delete(obj.t);
end
function set_time(obj, event, arg)
arg.pb1.String = datestr(now);
end
function my_callback_fcn(obj, event, arg)
txt1 = ' event occurred at ';
txt2 = arg;
event_type = event.Type;
event_time = datestr(event.Data.time);
msg = [event_type txt1 event_time];
disp(msg)
disp(txt2)
end

MATLAB: How to run function until the key is released?

I have a GUI and I want to repeat some process from the time the given key is pressed until the key is released.
I know how to do some process once when the key is pressed. But is there any way how to for example display random number every second until the key is released?
Thank you for your answers.
Jaja
You can attach a timer to your figure, start it with the KeyPressFcn and stop it with the KeyReleaseFcn.
The example below will create a figure, and display a random number in the console as long as the key f is pressed.
function h=keypressdemo
h.fig = figure ;
%// set up the timer
h.t = timer ;
h.t.Period = 1 ;
h.t.ExecutionMode = 'fixedRate' ;
h.t.TimerFcn = #timer_calback ;
%// set up the Key functions
set( h.fig , 'keyPressFcn' , #keyPressFcn_calback ) ;
set( h.fig , 'keyReleaseFcn' , #keyReleaseFcn_calback ) ;
guidata( h.fig ,h)
function timer_calback(~,~)
disp( rand(1) )
function keyPressFcn_calback(hobj,evt)
if strcmp(evt.Key,'f')
h = guidata(hobj) ;
%// necessary to check if the timer is already running
%// otherwise the automatic key repetition tries to start
%// the timer multiple time, which produces an error
if strcmp(h.t.Running,'off')
start(h.t)
end
end
function keyReleaseFcn_calback(hobj,evt)
if strcmp(evt.Key,'f')
h = guidata(hobj) ;
stop(h.t)
end
This is a simple timer mode and the callback function take a lot less time than the interval so no problem to expect here. If you want whatever function to re-execute itself right after it's finished (kind of infinite loop), you can set that up by changing the executionmode of the timer (read the timer documentation for examples.
However, be aware that if your callback execute permanently and consume all the (matlab unique) thread ressource, your GUI might become less responsive.