How do I break while loop using a switch in app designer
Show older comments
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
Answers (2)
Guillaume
on 2 Jun 2019
1 vote
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
Johnny Birch
on 3 Jun 2019
BRILLIANT, thanks a lot Guillaume.
Johnny Birch
on 3 Jun 2019
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".
Guillaume
on 4 Jun 2019
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
Johnny Birch
on 4 Jun 2019
Once again, thanks for you great help Guillaume
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
Guillaume
on 2 Jun 2019
Note that the Value property of a StateButton is either 0 or 1. It's not the same as its Text property. There's also not much point in the Inprocess indirection, you may as well do the timer start/stop inside the switch (or better an if|):
function SwitchValueChanged(app, event)
if app.Switch.Value
app.InProcessLamp.Color = 'green';
start(app.Timer);
else
app.InProcessLamp.Color = 'red';
stop(app.Timer);
end
end
Johnny Birch
on 2 Jun 2019
Geoff Hayes
on 2 Jun 2019
Johnny - why not use a timer to do that? It can periodically "monitor" your folder and move any files found there to the new folder destination. When finished, you could turn the timer off.
Johnny Birch
on 2 Jun 2019
Geoff Hayes
on 2 Jun 2019
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.
Guillaume
on 2 Jun 2019
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.
Johnny Birch
on 2 Jun 2019
Categories
Find more on Code Execution in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!