MATLAB Answers

0

How do I break while loop using a switch in app designer

Asked by Johnny Birch on 2 Jun 2019
Latest activity Commented on by Johnny Birch on 4 Jun 2019
I'm working on a GUI using App Designer. I want to control an continues while loop from a switch. So far I can initiate the loop by turning the switch to "go" (see code below) but I am unable to break the loop when I switch it to "stop". I get the 'STOP' printed to my command window, but it then contiues to count.
The output I get is "1234STOP567..." where the while loop contines until i manually break it [ctrl+c].
How do I break the while loop when I turn the switch to 'Stop'?
Thanks
% Value changed function: Switch
function SwitchValueChanged(app, event)
switch app.Switch.Value
case 'Go'
app.InProcessLamp.Color = 'green';
InProcess = 1;
case 'Stop'
app.InProcessLamp.Color = 'red';
InProcess = 0;
end
n = 0;
while true
pause(2)
if InProcess == 0
fprintf('STOP'); %skal fjernes
break;
end
n = n+1;
fprintf(num2str(n));
pause(2);
end
end

  0 Comments

Sign in to comment.

Products


Release

R2019a

2 Answers

Answer by Guillaume
on 2 Jun 2019

As I said, a much cleaner design is to have the timer as an App property and initialise it int the StartupFcn. The only thing you'd do in the callback is start and stop it instead of creating and destroying timers.
The default 'ExecutionMode' of timers is 'SingleShot' so they only execute once. If you want a periodic timer you need to specify a different execution mode such as 'FixedRate'.
Attached an example App.

  4 Comments

Show 1 older comment
Hi Guillaume,
One final question, please. If I have an EditField box in my app whre I want the inputted string called from the "mytimercallback(~, ~, ~)" function.
I would prefer to have a function inside the "mytimercallback(~, ~, ~)" function.
How can I do this? I have modified you code a bit and included it here as app1new. When I run it i get the following error message:
This message is sent at time 19:19:16.520
Error while evaluating TimerFcn for timer 'timer-1'
Undefined variable "app" or class "app.EditField.Value".
mytimercallback is a class method like any other so its first input (which I ignored since we werent' using it) is going to be the app. The only thing you have to do is not ignore it:
function mytimercallback(app, ~, ~)
%code that uses the app input argument
end
Once again, thanks for you great help Guillaume

Sign in to comment.


Answer by Geoff Hayes
on 2 Jun 2019

Johnny - without knowing how SwitchValueChanged is called, I suspect that the problem might be because this function ends up being called twice: the first time when the app.Switch.Value is true and the second time when this variable is false. So the first call to this function keeps going "forever" since it is not aware of the change to app.Switch.Value while the contribution of the call to this function a second time is to just to write STOP to the console and it will have no impact on the while loop that is continuing in the first call to this function.
With GUIDE, you could get around this problem by querying - on every iteration fo the while loop - the state of the app.Switch.Value (assuming this value was accessbile from a uicontrol or through an updated copy of the handles structure. For App Designer, I'm not sure how you would do this (continually check the state of app.Switch.Value from within the while loop??)
Alternatively, you may want to consider using a timer object instead of a while loop which would mean that your SwitchValueChanged would become something like
function SwitchValueChanged(app, event)
switch app.Switch.Value
case 'Go'
app.InProcessLamp.Color = 'green';
InProcess = 1;
case 'Stop'
app.InProcessLamp.Color = 'red';
InProcess = 0;
end
if InProcess
% start your timer
else
% stop your timer
end
end
You would need to save the handle to the timer object (somewher in the app) so that you can stop it. Note that once you start the timer, your call to SwitchValueChanged will complete so that the next time you call this function, there will not be an already running call of it.

  7 Comments

Johnny - take a look at the documentation for the timer object. You will need to do something like
function SwitchValueChanged(app, event)
if app.Switch.Value
% start your timer
t = timer;
t.Period = 35
t.TimerFcn = @myTimerCallback;
start(t)
% save the timer object to the app
% ???
else
% stop your timer
% get your timer object from the app
% ???
t = ...;
stop(t);
end
end
function myTimerCallback(mTimer, ~)
% query your folder for new files
% move the new files
end
I'm just not sure on how to save the timer object to the app. It could be as simple as doing app.timerObj = t; but I haven't used App Designer to know for sure.
Apps are just classes, you'd define the timer as a property of the class, and initialise it in the App StartupFcn.
Note that if on Windows, I'd consider using .Net FileSystemWatcher instead of a Timer. There are a few examples on Answer on how to do that (this is one of mine). For all OSes, you can also use Java WatchService but it's more complicated. See this Answer where I worked it out.
The advantages of the watchers is that you don't have to do any polling, you just wait to get notified that the file has changed.
Once again, thanks for you help.
I have one last issue. I can call the function by use of Geoff's code modified to below code, but I would expect the code to run my function every 2 second and therefore give a updatede timestamp in the Command Window. But I only get the first timestamp when I switch in on, but no following timestamps. What am I missing?
% Value changed function: Switch
function SwitchValueChanged(app, event)
switch app.Switch.Value
case 'Go'
app.InProcessLamp.Color = 'green';
InProcess = 1;
case 'Stop'
app.InProcessLamp.Color = 'red';
InProcess = 0;
end
assignin('base','InProcess',InProcess);
% start your timer
t = timer;
if InProcess == 1
t.Period = 2;
t.TimerFcn = @myTimerCallback;
start(t)
out = isvalid(t);
else
stop(t)
delete(t)
out = isvalid(t);
end
assignin('base','out',out);
function myTimerCallback(t, ~)
% query your folder for new files
fprintf('This message is sent at time %s\n', datestr(now,'HH:MM:SS.FFF'));
% move the new files
end

Sign in to comment.