How do I exit a loop?! (Solved)

Hello. Please forgive me if this has been answered somewhere before, but I am not finding it if it has.

I am trying to rewrite a rather complex app in Xojo from VB6, and I am finding that Xojo uses a very different development paradigm. I basically taught myself to program in VB5/6 by writing this app over the course of six or seven years as a hobby, and the source code is lost, so I must rewrite it from scratch in order to improve and update it. I don’t claim to be any sort of expert in programming.

That said, I am currently attempting to find a solution for what was a very simple issue in VB. I have a set of nested loops in the Start button and I need to have the ability to stop the loop during execution if the user so wishes. These loops can literally require tens or hundreds of hours to complete otherwise. In VB, I simply used DoEvents in the innermost loop and allowed the system to relinquish time to the rest of the app so that if the Stop button was pressed, it would be able to change the state of a variable, ExitLoop to True. In the innermost of the nested loops, I had a check to see if the state of ExitLoop was true or not. If it was, then I had execution jump to an identifier outside the loop.

Xojo is definitely doing things very differently. DoEvents does not exist by itself, and even as app.DoEvents or app.DoEvents(1) does not work; the debugger is evoked and I am informed that “This item does not exist.” Some forum posts I read say that calling this from a GUI app is not good anyway.

I am not finding anything here that I can use to get the system to relinquish time for other parts of the UI to be accessible and potentially exit such a loop. At least nothing I am understanding yet, if there is something for doing that listed on the forum. Obviously I would not be asking for help if I could find it myself. :slight_smile:

So how then do I offer the user the option of not having to sit through tens or hundreds of hours of loop execution if they choose to stop the loop early? I’m at a loss. Thanks for your patience and help.

You could use threads - see http://documentation.xojo.com/index.php/Thread

Have a boolean variable StopProcessing that the user can set, and inside your thread check for its state.

If StopProcessing is True then do some clean-up and then terminate the thread.

Thanks for your help, Markus. I’m not yet familiar with threads use in programming, I will have to read up on this.

If you are referring to things like a FOR/NEXT or WHILE/WEND loop you can use the EXIT verb.

http://documentation.xojo.com/index.php/Exit

If it’s loops that will take hours to process then you must thread them or the user would never be able to click the Stop button, as the interface would be locked up.

Here is a bit more detailed idea.

Set up a Boolean property that is set via a user interface button (Cancel).

Setup your loop in a thread (they are pretty easy to use) or a timer that is set to ModeSingle (only fires once). If you use the timer idea it can be set to ModeOff and when you are ready for your process to run set it to ModeSingle.

In the middle of the loop you can check the Boolean property to see if it has been set to TRUE and use the EXIT verb to exit your nested loops and gracefully exit the thread or timer.

If you like to update the display while a long running loop is active I will sometimes create a timer that ticks once per second and have it look at a property that is being updated by the loop (like a counter) and display that value or update a progress bar. This may be better than trying to continuously update a screen value for a loop that will continue for thousands of iterations. This is less overhead to have the timer update once per second or what ever period is useful. The thread for the main processing loop can turn off the display update timer just before exit.

This sounds like a desktop app but later if you create Web Apps threads cannot “see” session properties and methods without some special coding. Because of that “quirk” I like to use Timers in Web Apps.

Okay, so I have replaced the code in the Start button with a thread named ThreadStartExecutionConsecutive and put the code previously in the button, in the thread.

This is failing because I cannot seem to get the Boolean variable ExitLoop to exist, regardless of use of the Dim statement in the thread. This is the code, if it helps…


Dim A, B, C, D, E, F, X, as Variant
Dim ExitLoop as Boolean

ExitLoop = False

A = 1
B = A + 1
C = B + 1
D = C + 1
E = D + 1
F = E + 1

For A = 1 to 48
For B = (A+1) to 49
For C = (B + 1) to 50
For D = (C + 1) to 51
For E = (D + 1) to 52
For F = (E + 1) to 53

          If ExitLoop = True then GoTo OutOfLoop
          
          
          TxtLastSetGenerated.Text = A + " " + B + " " + C + " " + D + " " + E + " " + F
          TxtLastSetGenerated.Refresh
          
        Next F
      Next E
    Next D
  Next C
Next B

Next A

OutOfLoop:

ExitLoop = False


This has the program telling me ExitLoop does not exist. Very confused by this.

Does Xojo still have a GoTo? The docs says it has. Mind-boggling!!!

Anyhow: in Xojo you rarely need variants, really. Your boolean is automatically initialized as false. Even so you can do this in one row.

What is your code supposed to do? Don’t you need some condition for having exitLoop = false or true? Why don’t you put your code into a single function and simply use a return? See http://documentation.xojo.com/index.php/Return. In pseudo code:

[code]TxtLastSetGenerated.Text = calcMyText

function calcMyText as string
dim theResult as string
'code for function here
if exitLoop then return theResult
end function[/code]

Goto is not evil. When you abuse it, it is evil, just like any other language aspect. Goto has a bad name from when it was the only want to jump around in code. In our code we have a goto use here and there in some pretty complex code. Makes life much easier. A few uses per 150k LOC isn’t going to make a mess of your code or make it hard to read, don’t be afraid of it but don’t abuse it either.

Is the code you posted the entire method? It seems like surely something is missing. Can you copy/paste your code into here? Please wrap it with [ code ]…[ /code ] blocks (without the spaces around [) to make it much more readable.

Your ‘ExitLoop’ variable needs to be declared in the window or a module for it to be accessible outside the thread. Add it as a property of the window and remove the ‘Dim’ statement.

All variables have a “scope”, meaning where they are accessible depends on how you set them up.

If you declare a variable inside a method then that variable disappears when the method ends.

So as Mark said declare the variable somewhere where it will persist, like the window (will persist as long as the window exists) or a module (will persist as long as the app runs).

I would also recommend showing more of your code here. If it runs for hundreds of hours then I’m sure some people here would love to have a go at improving it.

P.S. To be clear, add ExitLoop as a boolean property to a module.

Fir example the following is completely unnecessary and can be deleted

A = 1 B = A + 1 C = B + 1 D = C + 1 E = D + 1 F = E + 1

as you set the value in the loops anyway

For A = 1 to 48 For B = (A+1) to 49 For C = (B + 1) to 50 For D = (C + 1) to 51 For E = (D + 1) to 52 For F = (E + 1) to 53

Btw you are running a total of 12,230,590,464 loops.

Each loop you create a text and set a textfield (?) to it? Probably so fast that you can’t even see it (which makes it pointless).

I’m not sure the program actually generates what you think it generates. What are you actually trying to achieve?

I’m actually attempting to reconstruct this code from memory and this is pretty much day one. The code you see is all I have yet, before I hit this snag. I’m also returning to programming after several years away, so I’m a bit rusty on top of being new to Xojo language. I sometimes will put stuff in code and then later realize, oh, yeah, that’s redundant.

The textfields, are on the UI, and I’m not creating them, but adjusting the text value. Basically this is a program intended to create all possible combinations of numbers in a lottery game. Later, I will be adding user configurable filters in the innermost loop. But that’s the purpose of the loops. Some lottery games are much bigger than 6/53. It generates the right results, but I had no way to exit the loop during testing.

Sorry about the lack of [ code ]…[ /code ] blocks.

I played with modules for a bit, but got very confused. Now that I know I am looking at adding it as a property, I’ll see if I can figure that out.

Wow, you guys are all really responsive, thank you. I’ll try to figure as much out on my own so you guys aren’t wasting your time, but wow, Xojo sure does things differently than what I muddled through teaching myself in VB, I guess. I see that I will be learning this language a lot better with all the help!

Off to figure out making ExitLoop a property.

If I make the ExitLoop a property of the window, it has a scope option of private, protected or public. If I make it in a module, it can be global, too. Don’t I want global?

Global is good here.

This is very strange… I added a module which I named Globals, and then created an ExitLoop property as a Boolean, which defaults to false. The entire UI disappeared… It’s no longer listed in the panel to the left, and none of the visible components are either. I have the application superclass showing, and it’s constants and event handler; the main menu bar; and the module globals with its property. I think somehow the rest got deleted, which I did not see happen. But I’m pretty sure it’s gone because when I try to run the program, it does nothing and returns me to the compiler, and the compiler window says “No Editor” for the superclass. Is this a bug or did I somehow highlight and delete the whole UI? In either case, I’m screwed, and it’ll take me bit to rebuild it.

Try

[code] Dim A, B, C, D, E, F as Integer // don’t use variants

dim GeneratedText() as string // make a string array to hold all the results
dim LastGeneratedText(5) as string // make a string array to hold the last calculated result

// NOTE: arrays start at 0

A = 1
B = 2
C = 3
D = 4
E = 5
F = 6

For A = 1 to 48 // used 5 in my example output
For B = (A+1) to 49 // used 6 in my example output
For C = (B + 1) to 50 // used 7 in my example output
For D = (C + 1) to 51 // used 8 in my example output
For E = (D + 1) to 52 // used 9 in my example output
For F = (E + 1) to 53 // used 10 in my example output

          LastGeneratedText(0) = Str( A )  // turn the integer into text and store it in the array
          LastGeneratedText(1) = Str( B )
          LastGeneratedText(2) = Str( C )
          LastGeneratedText(3) = Str( D )
          LastGeneratedText(4) = Str( E )
          LastGeneratedText(5) = Str( F )
          
          // join the array entries with a space between them and 
         // append the generated text to the other array
          GeneratedText.append Join( LastGeneratedText, " " )  
          
        Next F
      Next E
    Next D
  Next C
Next B

Next A

TextArea1.text = Join( GeneratedText, EndOfLine ) // join all the lines and put an EndOfLine between them [/code]

Note that setting the text in each loop (and there are a LOT of loops) and refreshing the display is time consuming. It is also unnecessary as you can’t see the text.

This should be somewhat faster but I’m sure it could be much faster …

Example project at https://dl.dropboxusercontent.com/u/992591/Xojo/Forum/Loop.rbp.zip

The output looks like this:

1 2 3 4 5 6
1 2 3 4 5 7
1 2 3 4 5 8
1 2 3 4 5 9
1 2 3 4 5 10
1 2 3 4 6 7
1 2 3 4 6 8
1 2 3 4 6 9
1 2 3 4 6 10
1 2 3 4 7 8
1 2 3 4 7 9
1 2 3 4 7 10
1 2 3 4 8 9
1 2 3 4 8 10
1 2 3 4 9 10
1 2 3 5 6 7
1 2 3 5 6 8
1 2 3 5 6 9
1 2 3 5 6 10
1 2 3 5 7 8
1 2 3 5 7 9
1 2 3 5 7 10
1 2 3 5 8 9
1 2 3 5 8 10
1 2 3 5 9 10
1 2 3 6 7 8
1 2 3 6 7 9
1 2 3 6 7 10
1 2 3 6 8 9
1 2 3 6 8 10
1 2 3 6 9 10
1 2 3 7 8 9
1 2 3 7 8 10
1 2 3 7 9 10
1 2 3 8 9 10
1 2 4 5 6 7
1 2 4 5 6 8
1 2 4 5 6 9
1 2 4 5 6 10
1 2 4 5 7 8
1 2 4 5 7 9
1 2 4 5 7 10
1 2 4 5 8 9
1 2 4 5 8 10
1 2 4 5 9 10
1 2 4 6 7 8
1 2 4 6 7 9
1 2 4 6 7 10
1 2 4 6 8 9
1 2 4 6 8 10
1 2 4 6 9 10
1 2 4 7 8 9
1 2 4 7 8 10
1 2 4 7 9 10
1 2 4 8 9 10
1 2 5 6 7 8
1 2 5 6 7 9
…

I improved the example project (it now uses a thread and the calculation can be stopped). Same link.

Example project at https://dl.dropboxusercontent.com/u/992591/Xojo/Forum/Loop.rbp.zip