How can I stop a loop with an event?

Hi,

In developing of my App, i have two problem  caused by the fact that I do not understand how to stop a loop with an event.

I have written the following code to replicate this problem.

In my App there is a complex model that takes up to two minutes of time to calculate the solution.
I would like to have the possibility to show the time that pass during the calculation and to stop or start again the calculation through the click on two differents buttons (in the code are two circles for simplicity)

How is visible from the following code, I can view the time passing and stop the loop only when the same loop is finished.

Someone has already had this issue?

Sorry for my english.

Thanks for the tips that will come

regards, 

Gianluca

local calculation\_progress=true local messagge\_obj=display.newText("Start Calculation",display.contentCenterX-200, display.contentCenterY-200, native.systemFont, 40) messagge\_obj:setTextColor( 255, 255, 255 ) --- here there is a simple function, but in my App is a complex loop that works until 2 minutes local function loop\_fun() messagge\_obj.text="Calculation started" local max\_comps=1000000 for i=1,max\_comps do if calculation\_progress==true then local messagge\_loop=tostring(i) --- here is a simple model print(messagge\_loop) else break end end messagge\_obj.text="Calculation done" end --- setting of the timer local test\_time\_label = display.newText("Time:", display.contentCenterX-125, display.contentCenterY-50, native.systemFont, 40 ) local test\_time = display.newText("", display.contentCenterX-20, display.contentCenterY-10, native.systemFont, 40 ) local function refresh\_time() local currentTime = os.date("\*t") test\_time.text=os.time( t ) --currentTime end Runtime:addEventListener("enterFrame", refresh\_time) --- setting of play and stop button local function play\_calc() calculation\_progress=true loop\_fun() print("calculation\_progress",calculation\_progress) end local function stop\_calc() calculation\_progress=false print("calculation\_progress",calculation\_progress) end local myButton\_calc\_play = display.newCircle(display.contentCenterX+60,display.contentCenterY+200,60) local test\_play = display.newText("Play", display.contentCenterX+10,display.contentCenterY+180, native.systemFont, 45 ) test\_play:setTextColor(0) test\_play:addEventListener("tap", play\_calc) local myButton\_calc\_stop = display.newCircle(display.contentCenterX-100,display.contentCenterY+200,60) local test\_stop = display.newText("Stop", display.contentCenterX-145,display.contentCenterY+180, native.systemFont, 45 ) test\_stop:setTextColor(0) test\_stop:addEventListener("tap", stop\_calc)

There are almost forty visits, but no response.

I hope my question is not too complicated. For me it is a serious problem. With the code posted I can not stop the loop with an event triggered by a click.

No one has any advice for me? Some of the staff of Corona SDK can you please answer me? I believe that an expert has already encountered this problem and solved it.

regards,

Gianluca

Perhaps ‘break’ is just breaking out of the first condition - try changing that to return.

I am struggling to understand the architecture behind your code - perhaps there is a more elegant solution or better design pattern?

Hi SegaBoy,

thanks for replay.

The code posted is just a demo made ​​to highlight the problem that I’m trying to solve with my App.

The heart of the problem is that I have a model that computes a solution in 2 minutes, but I would like to give to user the ability to stop it with a click.

I have changed the code with you advice, i have put “return” instead of “break”, but is not the solution.

If you run my code with simulator and then click on “Play” button, you see that you can’t stop the loop with a click on “Stop” button.

The loop continue until the end without that the user can stop it.

Below the code changed

regards,

Gianluca

local calculation\_progress=true local messagge\_obj=display.newText("Start Calculation",display.contentCenterX-200, display.contentCenterY-200, native.systemFont, 40) messagge\_obj:setTextColor( 255, 255, 255 ) --- here there is a simple function, but in my App is a complex loop that works until 2 minutes local function loop\_fun() local max\_comps=100000 for i=1,max\_comps do if calculation\_progress==true then local messagge\_loop=tostring(i) --- here is a simple model print(messagge\_loop) else messagge\_obj.text="Calculation stopped" return 0 end end messagge\_obj.text="Calculation done" end --- setting of the timer local test\_time\_label = display.newText("Time:", display.contentCenterX-125, display.contentCenterY-50, native.systemFont, 40 ) local test\_time = display.newText("", display.contentCenterX-20, display.contentCenterY-10, native.systemFont, 40 ) local function refresh\_time() local currentTime = os.date("\*t") test\_time.text=os.time( t ) --currentTime end Runtime:addEventListener("enterFrame", refresh\_time) --- setting of play and stop button local function play\_calc() messagge\_obj.text="Calculation started" calculation\_progress=true loop\_fun() print("calculation\_progress",calculation\_progress) end local function stop\_calc() calculation\_progress=false print("calculation\_progress",calculation\_progress) end local myButton\_calc\_play = display.newCircle(display.contentCenterX+60,display.contentCenterY+200,60) local test\_play = display.newText("Play", display.contentCenterX+10,display.contentCenterY+180, native.systemFont, 45 ) test\_play:setTextColor(0) test\_play:addEventListener("tap", play\_calc) local myButton\_calc\_stop = display.newCircle(display.contentCenterX-100,display.contentCenterY+200,60) local test\_stop = display.newText("Stop", display.contentCenterX-145,display.contentCenterY+180, native.systemFont, 45 ) test\_stop:setTextColor(0) test\_stop:addEventListener("tap", stop\_calc)

One option might be to get rid of the separate loop_fun function and include that functionality inside the enterFrame/refresh_time function … with a small piece of the larger loop happening for each enterFrame event.

If the smallest unit of calculation is still too big, then maybe put it all into a timer loop (maybe do 10 “inner iterations” per timer?):

-- global iteration count local i = 0 local max\_comps = 100000 local function doWork( e ) if( i \> max\_comps ) then -- we're all done -- trigger other events? -- stop any more calculations calc\_progress = false end if( calc\_progress == true ) then -- do the work for iteration i local message = tostring(i) print( message ) i = i + 1 end -- print elapsed time local currentTime = os.date("\*t") test\_time.text = os.time( t ) end timer.performWithDelay( 100, doWork, 0 )

Resolved!!!

Thank you very much jbp1 for your advice.

Following your indication I replaced the for cicle with timer.performWithDelay.

Now the demo of my problem works fine.

Below the code with the change.

local calculation\_progress=true local messagge\_obj=display.newText("Start Calculation",display.contentCenterX-200, display.contentCenterY-200, native.systemFont, 40) messagge\_obj:setTextColor( 255, 255, 255 ) --- function to exit from loop function verify\_progress\_loop() local outcome=true if calculation\_progress==false then outcome=false end return outcome end --- here there is a simple function, but in my App is a complex loop that works until 2 minutes local max\_comps=100000 local n\_min\_cicle=100 local n\_delay=max\_comps/n\_min\_cicle local function loop\_fun() local t local i=0 local function doWork() for j=1,n\_min\_cicle do local outcome=verify\_progress\_loop() if outcome==true then local messagge\_loop=tostring(i) --- here is a simple model print(messagge\_loop) else messagge\_obj.text="Calculation stopped" timer.cancel(t) --return 0 end i=i+1 if i==max\_comps then messagge\_obj.text="Calculation done" timer.cancel(t) end end end t=timer.performWithDelay( 0.1, doWork, n\_delay ) end --- setting of the timer local test\_time\_label = display.newText("Time:", display.contentCenterX-125, display.contentCenterY-50, native.systemFont, 40 ) local test\_time = display.newText("", display.contentCenterX-20, display.contentCenterY-10, native.systemFont, 40 ) local function refresh\_time() local currentTime = os.date("\*t") test\_time.text=os.time( t ) --currentTime end Runtime:addEventListener("enterFrame", refresh\_time) --- setting of play and stop button local function play\_calc(event) messagge\_obj.text="Calculation started" calculation\_progress=true loop\_fun() print("Inside play\_cal function") return true end local function stop\_calc(event) calculation\_progress=false print("Inside stop\_cal function") return true end local myButton\_calc\_play = display.newCircle(display.contentCenterX+60,display.contentCenterY+200,60) local test\_play = display.newText("Play", display.contentCenterX+10,display.contentCenterY+180, native.systemFont, 45 ) test\_play:setTextColor(0) test\_play:addEventListener("tap", play\_calc) local myButton\_calc\_stop = display.newCircle(display.contentCenterX-100,display.contentCenterY+200,60) local test\_stop = display.newText("Stop", display.contentCenterX-145,display.contentCenterY+180, native.systemFont, 45 ) test\_stop:setTextColor(0) test\_stop:addEventListener("tap", stop\_calc)

There is another way to resolve the problem, but using the coroutines.

I prefer this method because allows you to not cut into several pieces the code of the main loop (where there is model with the calculation that involves several minutes).

Below the code is changed.

local calculation\_progress=false local messagge\_obj=display.newText("Start Calculation",display.contentCenterX-200, display.contentCenterY-200, native.systemFont, 40) messagge\_obj:setTextColor( 255, 255, 255 ) --- here there is a simple function, but in my App is a complex loop that works until 2 minutes local function loop\_fun() messagge\_obj.text="Calculation started" local max\_comps=1000 for i=1,max\_comps do if calculation\_progress==true then local messagge\_loop=tostring(i) --- here is a simple model print(messagge\_loop) else return 0 end coroutine.yield() end messagge\_obj.text="Calculation done" end --- setting of the timer local test\_time\_label = display.newText("Time:", display.contentCenterX-125, display.contentCenterY-50, native.systemFont, 40 ) local test\_time = display.newText("", display.contentCenterX-20, display.contentCenterY-10, native.systemFont, 40 ) local function refresh\_time() local currentTime = os.date("\*t") test\_time.text=os.time( t ) --currentTime end Runtime:addEventListener("enterFrame", refresh\_time) --- setting of play and stop button local function play\_calc() calculation\_progress=true print("calculation\_progress",calculation\_progress) co = coroutine.create(loop\_fun) print(co,coroutine.status(co)) coroutine.resume(co) end local function verify\_loop\_status() if calculation\_progress==true then coroutine.resume(co) end end local function stop\_calc() calculation\_progress=false print("calculation\_progress",calculation\_progress) end Runtime:addEventListener("enterFrame", verify\_loop\_status)

There are almost forty visits, but no response.

I hope my question is not too complicated. For me it is a serious problem. With the code posted I can not stop the loop with an event triggered by a click.

No one has any advice for me? Some of the staff of Corona SDK can you please answer me? I believe that an expert has already encountered this problem and solved it.

regards,

Gianluca

Perhaps ‘break’ is just breaking out of the first condition - try changing that to return.

I am struggling to understand the architecture behind your code - perhaps there is a more elegant solution or better design pattern?

Hi SegaBoy,

thanks for replay.

The code posted is just a demo made ​​to highlight the problem that I’m trying to solve with my App.

The heart of the problem is that I have a model that computes a solution in 2 minutes, but I would like to give to user the ability to stop it with a click.

I have changed the code with you advice, i have put “return” instead of “break”, but is not the solution.

If you run my code with simulator and then click on “Play” button, you see that you can’t stop the loop with a click on “Stop” button.

The loop continue until the end without that the user can stop it.

Below the code changed

regards,

Gianluca

local calculation\_progress=true local messagge\_obj=display.newText("Start Calculation",display.contentCenterX-200, display.contentCenterY-200, native.systemFont, 40) messagge\_obj:setTextColor( 255, 255, 255 ) --- here there is a simple function, but in my App is a complex loop that works until 2 minutes local function loop\_fun() local max\_comps=100000 for i=1,max\_comps do if calculation\_progress==true then local messagge\_loop=tostring(i) --- here is a simple model print(messagge\_loop) else messagge\_obj.text="Calculation stopped" return 0 end end messagge\_obj.text="Calculation done" end --- setting of the timer local test\_time\_label = display.newText("Time:", display.contentCenterX-125, display.contentCenterY-50, native.systemFont, 40 ) local test\_time = display.newText("", display.contentCenterX-20, display.contentCenterY-10, native.systemFont, 40 ) local function refresh\_time() local currentTime = os.date("\*t") test\_time.text=os.time( t ) --currentTime end Runtime:addEventListener("enterFrame", refresh\_time) --- setting of play and stop button local function play\_calc() messagge\_obj.text="Calculation started" calculation\_progress=true loop\_fun() print("calculation\_progress",calculation\_progress) end local function stop\_calc() calculation\_progress=false print("calculation\_progress",calculation\_progress) end local myButton\_calc\_play = display.newCircle(display.contentCenterX+60,display.contentCenterY+200,60) local test\_play = display.newText("Play", display.contentCenterX+10,display.contentCenterY+180, native.systemFont, 45 ) test\_play:setTextColor(0) test\_play:addEventListener("tap", play\_calc) local myButton\_calc\_stop = display.newCircle(display.contentCenterX-100,display.contentCenterY+200,60) local test\_stop = display.newText("Stop", display.contentCenterX-145,display.contentCenterY+180, native.systemFont, 45 ) test\_stop:setTextColor(0) test\_stop:addEventListener("tap", stop\_calc)

One option might be to get rid of the separate loop_fun function and include that functionality inside the enterFrame/refresh_time function … with a small piece of the larger loop happening for each enterFrame event.

If the smallest unit of calculation is still too big, then maybe put it all into a timer loop (maybe do 10 “inner iterations” per timer?):

-- global iteration count local i = 0 local max\_comps = 100000 local function doWork( e ) if( i \> max\_comps ) then -- we're all done -- trigger other events? -- stop any more calculations calc\_progress = false end if( calc\_progress == true ) then -- do the work for iteration i local message = tostring(i) print( message ) i = i + 1 end -- print elapsed time local currentTime = os.date("\*t") test\_time.text = os.time( t ) end timer.performWithDelay( 100, doWork, 0 )

Resolved!!!

Thank you very much jbp1 for your advice.

Following your indication I replaced the for cicle with timer.performWithDelay.

Now the demo of my problem works fine.

Below the code with the change.

local calculation\_progress=true local messagge\_obj=display.newText("Start Calculation",display.contentCenterX-200, display.contentCenterY-200, native.systemFont, 40) messagge\_obj:setTextColor( 255, 255, 255 ) --- function to exit from loop function verify\_progress\_loop() local outcome=true if calculation\_progress==false then outcome=false end return outcome end --- here there is a simple function, but in my App is a complex loop that works until 2 minutes local max\_comps=100000 local n\_min\_cicle=100 local n\_delay=max\_comps/n\_min\_cicle local function loop\_fun() local t local i=0 local function doWork() for j=1,n\_min\_cicle do local outcome=verify\_progress\_loop() if outcome==true then local messagge\_loop=tostring(i) --- here is a simple model print(messagge\_loop) else messagge\_obj.text="Calculation stopped" timer.cancel(t) --return 0 end i=i+1 if i==max\_comps then messagge\_obj.text="Calculation done" timer.cancel(t) end end end t=timer.performWithDelay( 0.1, doWork, n\_delay ) end --- setting of the timer local test\_time\_label = display.newText("Time:", display.contentCenterX-125, display.contentCenterY-50, native.systemFont, 40 ) local test\_time = display.newText("", display.contentCenterX-20, display.contentCenterY-10, native.systemFont, 40 ) local function refresh\_time() local currentTime = os.date("\*t") test\_time.text=os.time( t ) --currentTime end Runtime:addEventListener("enterFrame", refresh\_time) --- setting of play and stop button local function play\_calc(event) messagge\_obj.text="Calculation started" calculation\_progress=true loop\_fun() print("Inside play\_cal function") return true end local function stop\_calc(event) calculation\_progress=false print("Inside stop\_cal function") return true end local myButton\_calc\_play = display.newCircle(display.contentCenterX+60,display.contentCenterY+200,60) local test\_play = display.newText("Play", display.contentCenterX+10,display.contentCenterY+180, native.systemFont, 45 ) test\_play:setTextColor(0) test\_play:addEventListener("tap", play\_calc) local myButton\_calc\_stop = display.newCircle(display.contentCenterX-100,display.contentCenterY+200,60) local test\_stop = display.newText("Stop", display.contentCenterX-145,display.contentCenterY+180, native.systemFont, 45 ) test\_stop:setTextColor(0) test\_stop:addEventListener("tap", stop\_calc)

There is another way to resolve the problem, but using the coroutines.

I prefer this method because allows you to not cut into several pieces the code of the main loop (where there is model with the calculation that involves several minutes).

Below the code is changed.

local calculation\_progress=false local messagge\_obj=display.newText("Start Calculation",display.contentCenterX-200, display.contentCenterY-200, native.systemFont, 40) messagge\_obj:setTextColor( 255, 255, 255 ) --- here there is a simple function, but in my App is a complex loop that works until 2 minutes local function loop\_fun() messagge\_obj.text="Calculation started" local max\_comps=1000 for i=1,max\_comps do if calculation\_progress==true then local messagge\_loop=tostring(i) --- here is a simple model print(messagge\_loop) else return 0 end coroutine.yield() end messagge\_obj.text="Calculation done" end --- setting of the timer local test\_time\_label = display.newText("Time:", display.contentCenterX-125, display.contentCenterY-50, native.systemFont, 40 ) local test\_time = display.newText("", display.contentCenterX-20, display.contentCenterY-10, native.systemFont, 40 ) local function refresh\_time() local currentTime = os.date("\*t") test\_time.text=os.time( t ) --currentTime end Runtime:addEventListener("enterFrame", refresh\_time) --- setting of play and stop button local function play\_calc() calculation\_progress=true print("calculation\_progress",calculation\_progress) co = coroutine.create(loop\_fun) print(co,coroutine.status(co)) coroutine.resume(co) end local function verify\_loop\_status() if calculation\_progress==true then coroutine.resume(co) end end local function stop\_calc() calculation\_progress=false print("calculation\_progress",calculation\_progress) end Runtime:addEventListener("enterFrame", verify\_loop\_status)