Stopping a continuous loop
Stopping a continuous loop
Stopping a continuous loop
Stopping a continuous loop
Stopping a continuous loop
Stopping a continuous loop Stopping a continuous loop Stopping a continuous loop Stopping a continuous loop Stopping a continuous loop Stopping a continuous loop Stopping a continuous loop Stopping a continuous loop
Stopping a continuous loop Stopping a continuous loop
Stopping a continuous loop
Go Back  Xtreme Visual Basic Talk > > > Stopping a continuous loop


Reply
 
Thread Tools Display Modes
  #1  
Old 10-02-2014, 07:24 AM
VB_Alien VB_Alien is offline
Senior Contributor
 
Join Date: Apr 2004
Posts: 854
Default Stopping a continuous loop


I have a loop running in my program that keeps
looping until i set a boolean flag to false.

I have a button on the form that set that flag to false.

When i press that button, nothing happens for the
first time clicked but after the second click, the flag
is set to false.

I have a DoEvents coded inside the loop to give way
for other processes but apparently it doesn't work on
the first attempt to stop the loop.

I've used a Do loop, Do while loop, Do Until loop,
Loop Until, While loop and all do the same thing.

How can i stop a continuous loop on the first click
of a button or form closing?

Thank-you
Reply With Quote
  #2  
Old 10-02-2014, 01:45 PM
passel's Avatar
passelStopping a continuous loop passel is offline
Sinecure Expert

Super Moderator
* Guru *
 
Join Date: Jun 2003
Location: Upstate New York, usa
Posts: 8,024
Default

You haven't posted code that demonstrates the problem.
How do you get the code to loop, that is, where is the loop, how did you get it started?
Normally you shouldn't be using DoEvents. You could be running the loop in a background thread.

But for sake of argument and a quick test example, this code had no problem exiting the loop on the first click of the button that sets the boolean flag.
The sub that loops is called by one button, and another button sets the flag to have the loop exit.
Code:
Public Class Form1

  Dim timeToLeave As Boolean

  Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    Button1.Enabled = False
    timeToLeave = False
    LoopAlot()           'Call the routine that loops (won't be back until it exits)
    Debug.Print("LoopAlot exited")
    Button1.Enabled = True
  End Sub

  Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
    timeToLeave = True
  End Sub

  Private Sub LoopAlot()
    Do Until timeToLeave
      Application.DoEvents()
    Loop
  End Sub
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.
Reply With Quote
  #3  
Old 10-02-2014, 04:18 PM
VB_Alien VB_Alien is offline
Senior Contributor
 
Join Date: Apr 2004
Posts: 854
Default

Now that's odd. Your code works but mine was setup the
same way and it didn't work on the first button click.

I even started a new project with a simple loop in it
and that was it and it didn't even work.

Just for kicks, i started another project that is setup
like yours and it works when i disable the buttons
but when i don't, i have to click twice to get out of
the loop.

Here's my loop

Code:
 Private LeaveTheLoop As Boolean

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        ' Button1.Enabled = False
        ' Button2.Enabled = True
        LeaveTheLoop = False
        LoopMe()

    End Sub

    Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
        '  Button1.Enabled = True
        '  Button2.Enabled = False
        LeaveTheLoop = True
    End Sub

    Private Sub LoopMe()

        Do Until LeaveTheLoop = True
            Application.DoEvents()
            Me.Text = "Still in the loop"
        Loop
       
        Me.Text = "Outside the loop"
    End Sub
Same as your code, just add 2 buttons.
This is also how my original code is set up
and i get the same results.

Ultimately, i need to use this loop in a graphics
drawing routine and i need the loop to quite upon
exiting the form. As it is now, it won't exit while
the loop is processing.
Reply With Quote
  #4  
Old 10-02-2014, 04:32 PM
VB_Alien VB_Alien is offline
Senior Contributor
 
Join Date: Apr 2004
Posts: 854
Default

I stopped the disabling of buttons in your code
and it does the same thing as my code.

It won't exit the loop until the second button click.

The form will close but the IDE is still in run mode.
Reply With Quote
  #5  
Old 10-03-2014, 06:05 AM
passel's Avatar
passelStopping a continuous loop passel is offline
Sinecure Expert

Super Moderator
* Guru *
 
Join Date: Jun 2003
Location: Upstate New York, usa
Posts: 8,024
Default

I assume it is because you're calling the sub from a button event, that event never completes, so the button up event gets hung up. By disabling the button frees up the event processing so the next button event is processed correctly.
If you don't disable the button the next button press is consumed internally somehow in windows in getting its event processing back in sync, so it takes one to "clean up", then normal button processing will work again.

Perhaps since you (apparently) need to draw in a continuous loop (instead of from a periodic event, like a timer tick), and you're using .Net, a different paradigm is needed.
Do your drawing in a background thread.
If you use a Buffered Graphics object your background thread can draw in it, and have it render to a control's area of the screen. It is technically not accessing the control or using it to draw so you don't have a cross threading issue.
Just don't drawn on that control from the GUI because it will be clobbered by the drawing from the background thread.
Don't know your complete situation though.

Here is a quick simple example that uses a Buffered Graphics object and a background thread to draw on the screen in the area "above" a panel.
To demonstrate it is drawing to the panel area, the example allows you to drag on the panel to move it around, while the background thread continues to draw to the screen area associated with that panel.

So, create a new project and add a panel to it, and make it whatever size you want, paste in the code and run it. Drag on the panel and see the drawing continue as the panel moves.
Another advantage to the background thread drawing to a Buffered Graphics object, is it continues to draw where drawing from the GUI pauses on some user interaction with the window, such as clicking down on the title bar of a window.
This also exits fine, it pauses for 1/10th of a second during closing to allow the loop to exit in the background thread. How long you have to pause depends on the frequency of your background thread loop.
Code:
Public Class Form1

  Dim thread1 As New Threading.Thread(AddressOf ThreadProc1)

  Dim appIsActive As Boolean = True
  Dim pnlHeight As Integer
  Dim pnlWidth As Integer

  Private Sub Form1_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
    appIsActive = False
    Threading.Thread.Sleep(100) 'allow the thread to exit
  End Sub

  Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    pnlHeight = Panel1.ClientSize.Height
    pnlWidth = Panel1.ClientSize.Width
    thread1.IsBackground = True
    thread1.Start()
  End Sub

  Private Sub ThreadProc1()
    Dim g As Graphics = Panel1.CreateGraphics  'Graphics object used to initialize the BufferedGraphics object, 
    '                                           which will be the default screen area render to
    Dim rect As New Rectangle(0, 0, 100, 100)  'A rectangle used to create random sized and positioned rectangles
    Dim sr As New Random                       'The random object used to fetch random numbers for generating random things
    Dim br As New SolidBrush(Color.White)      'A brush set to the random color to fill the random rectangles

    Dim gog As BufferedGraphics                'The BufferedGraphics object, used to do our backbuffer drawing and rendering
    Dim goc As BufferedGraphicsContext = BufferedGraphicsManager.Current 'Use the current bufferedGraphics manager for the form

    gog = goc.Allocate(g, New Rectangle(0, 0, pnlWidth, pnlHeight)) 'allocate our backbuffer drawing area 
    '                                                                and set the default graphics object to render to
    Dim gb As Graphics = gog.Graphics         'use a shorter name for the BufferedGraphics graphics object
    Do While appIsActive

      For i As Integer = 0 To 99
        rect.X = sr.Next(pnlWidth)
        rect.Y = sr.Next(pnlHeight)
        rect.Width = sr.Next(5, 100)
        rect.Height = sr.Next(5, 100)
        br.Color = Color.FromArgb(sr.Next(256), sr.Next(256), sr.Next(256))
        gb.FillRectangle(br, rect)
      Next
      gog.Render()
      Threading.Thread.Sleep(1)
    Loop
    goc.Dispose()
    g.Dispose()
    br.Dispose()
  End Sub

  Private Sub Panel1_MouseMove(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Panel1.MouseMove
    Dim pnl As Panel = DirectCast(sender, Panel)
    Static lp As Point
    If e.Button = Windows.Forms.MouseButtons.Left Then
      pnl.Left += e.X - lp.X
      pnl.Top += e.Y - lp.Y
    Else
      lp = e.Location
    End If
  End Sub

End Class
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.
Reply With Quote
  #6  
Old 10-03-2014, 10:46 AM
VB_Alien VB_Alien is offline
Senior Contributor
 
Join Date: Apr 2004
Posts: 854
Default

Wow!!! The graphics drawing on that panel made
my eyes go googly. LOL

I guess the background worker thread is the way
to go when using infinite loops. I was looking at
that myself yesterday but never used it before, so
i guess i shied away from it.

Thanks passel. You taught this old dog a new trick...
Reply With Quote
  #7  
Old 10-03-2014, 11:23 AM
VB_Alien VB_Alien is offline
Senior Contributor
 
Join Date: Apr 2004
Posts: 854
Default

Now i have a new problem the the background worker.

My loop is calling on 6 different subs to do some animation
rendering and it goes threw the first sub fine, until it
reaches the last line of code, which is:

picMap.Image = MapBmp

The error is say: Object is currently in use elsewhere

Any ideas on that one?
Reply With Quote
  #8  
Old 10-04-2014, 12:15 PM
VB_Alien VB_Alien is offline
Senior Contributor
 
Join Date: Apr 2004
Posts: 854
Default

I'm finding out that in a normal loop in a single
thread, the loop pulls the focus from all controls,
including the form. That is why i have to click
twice on the buttons to stop the drawing process
or click twice on the big red x button on the form
to close it.

The loop will exit on form closing when i use an
Application.Exit and the IDE goes back into design
mode.

I kind of like the background worker thread though
because you can move the form or do other stuff and
the drawing continues on. I like that aspect of it.

Like i said earlier though, i was getting an error, every
time i ran my program in the new thread. It was
complaining about using a picturebox object that was
still in use.

picMap.Image = MapBmp <-- Error here

The error is say: Object is currently in use elsewhere


I somewhat resolved that problem by eliminating every
picMap.Image = MapBmp in my code and only calling
that once in my loop. That works and all animations draw
correctly but there is still a problem.

When i resize the form and cover up some of the picturebox
(picMap), i get the same error. Now that i think of it, i'll try
using a try statement at that point to see if the helps.

According to MS, if you use a Synclock

Synclock(picMap)
' Code goes here
End Synclock

That is suppose to stop that kind of error from happening
but it doesn't.

It looks like the ThreadState has goes through many changes
from VB Net's very beginnings till now. A lot of the good
threadstates are now depreciated and no long used. So why
does MS still include them in the new versions of vb. For
backwards compatibility?

Anyway, just thought i'd give you an update on my problem.

No sure if i really need any help at this point. I'll post again
if i do.

Thank's for your help.
Reply With Quote
  #9  
Old 10-04-2014, 12:38 PM
VB_Alien VB_Alien is offline
Senior Contributor
 
Join Date: Apr 2004
Posts: 854
Default

Thought i would upload my animation demo, to let
you see what i was doing.

This started out as a high performance timer using
the QueryPerformanceCounter Api.

Then i found an old vb6 program that Noi_Max made
with the walking LOLO character(anyone remember that?),
that also used the QueryPerformanceCounter Api, so i
thought i'd try it in VB Net.

As you will see, it works pretty well.
Attached Files
File Type: zip HighPerformanceTimer.zip (88.1 KB, 10 views)
Reply With Quote
  #10  
Old 10-06-2014, 05:26 PM
passel's Avatar
passelStopping a continuous loop passel is offline
Sinecure Expert

Super Moderator
* Guru *
 
Join Date: Jun 2003
Location: Upstate New York, usa
Posts: 8,024
Default

Didn't look at my computer much at all this past weekend.
I'll look at your program tonight.
The issue is either that you're trying to access a GUI control from a background thread, which you can't do, you have to Invoke back to the GUI thread and access the control from there. That is the "paradigm" shift. You have to manage your drawing yourself and not use any GUI control methods, such as the paint event, to do any drawing.
Having code in the paint event I suspect is the problem with the picturebox being covered up.

The other possibility, since the error seems to indicate an object busy fault, not a control access fault, is you can't access an object from two threads at the same time.
A syncLock could help that, but it is best to avoid using the same object from multiple threads if the design allows it.

The StopWatch object essentially wraps access to the QueryPerformanceCounter in .Net, so you can use that more conveniently than having to use the API directly.

<edit>
I did some looking at your project.
I didn't relook at NOI_Max old VB6 code, and I assume he didn't have this mistake, but I was looking at the HpTimer.vb code to see how it looked, to see how one might replace it with a stopwatch object.
One think I noticed was it was taking a relatively large amount of time to complete each animation loop, more than I would have expected.
I started printing out the elapsed time each loop, and commenting out some things.
It turns out the drawing was what was taking the most time, so I looked at those animation code loops.
It looks like most of them have the "End If" in the wrong place (in front of the g.DrawImage call).
So you are drawing something for every tile of the map in every animation routing (except one sub, I think is correct).
The g.DrawImage should be inside the If Block, so that you only draw the animation tile once for each instance of that particular animation tile. You are essentially drawing each animation tile 77 times each frame.
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.

Last edited by passel; 10-06-2014 at 06:24 PM.
Reply With Quote
  #11  
Old 10-07-2014, 05:35 AM
VB_Alien VB_Alien is offline
Senior Contributor
 
Join Date: Apr 2004
Posts: 854
Default

Yes. It was an object busy fault. I put picMap.image = MapBmp
in the picmap paint event. Now picmap doesn't get called at all
in the background thread. Thanks for that idea.

I totally missed the drawing being done outside the if statement.
I put them all inside it. Thanks for pointing that out.

Some day, i may play with the stopwatch timer but for now, i'm
liking the QueryPerformanceCounter very much and i'm not ready
to scrap it out yet. It works very well, even in vb net. I think a
lot of programmers are still using it.
Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off

Forum Jump

Advertisement:





Free Publications
The ASP.NET 2.0 Anthology
101 Essential Tips, Tricks & Hacks - Free 156 Page Preview. Learn the most practical features and best approaches for ASP.NET.
subscribe
Programmers Heaven C# School Book -Free 338 Page eBook
The Programmers Heaven C# School book covers the .NET framework and the C# language.
subscribe
Build Your Own ASP.NET 3.5 Web Site Using C# & VB, 3rd Edition - Free 219 Page Preview!
This comprehensive step-by-step guide will help get your database-driven ASP.NET web site up and running in no time..
subscribe
Stopping a continuous loop
Stopping a continuous loop
Stopping a continuous loop Stopping a continuous loop
Stopping a continuous loop
Stopping a continuous loop
Stopping a continuous loop Stopping a continuous loop Stopping a continuous loop Stopping a continuous loop Stopping a continuous loop Stopping a continuous loop Stopping a continuous loop
Stopping a continuous loop
Stopping a continuous loop
 
Stopping a continuous loop
Stopping a continuous loop
 
-->