Simple Pause

Hi,

I'm trying to add pauses into one of my programs. If the pause is in a loop, the system hangs up on it. As a simple example, the following works fine - it waits 4 seconds then puts "5" in the label box:

Dim g As Integer = 5

System.Threading.Thread.Sleep(4000)

Label1.Text = g

The following code, however, doesn't work. It just hangs up and does nothing:

Dim g As Integer

For g = 1 To 10

System.Threading.Thread.Sleep(4000)

Label1.Text = g

Next

I'm just trying to throw in a pause during each iteration of the For loop.

I've tried the things mentioned in the threads "A Pause with a Loop" and "Simple delay needed", but nothing works. I'm using Visual Basic Express Edition 2005.

Any suggestions

Bob



Answer this question

Simple Pause

  • Wau

    If your prepared to accept a dead UI for 3 seconds then you can Use thread.sleep

    If your not then you can code alternatives - heres another than will maintain UI responsiveness during the 6 seconds delay.

    Public Class Form1
    Dim b As Boolean = False

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    Timer1.Interval = 6000
    Proc1()
    Proc2()

    Timer1.Enabled = True
    Do Until b = True
    Application.DoEvents()
    Loop

    b = False
    Proc3()
    End Sub

    Sub Proc1()
    Label1.Text = "Proc1"
    Application.DoEvents()
    End Sub

    Sub Proc2()
    label1.text = "Proc2"
    Application.DoEvents()
    End Sub

    Sub Proc3()
    label1.text = "Proc3"
    Application.DoEvents()
    End Sub

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
    b = True
    Timer1.Enabled = False
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    MsgBox("Foo")
    End Sub
    End Class


  • PDHB

    My question would be - what are you doing in you code that you want to intentionally slow the code down by putting a pause in there.

    Threading.Thread.Sleep is really a very quick and dirty way to put small pauses in an application as it will suspend the UI thread so the UI is essential dead.

    There are other ways to achieve this maybe by using a timer - which will keep the UI responsive for the duration.

    Let us know what you specifically trying to achieve with this delay and we can probably give you a better answer.


  • arashikage

    LOL @ Commadore 64

    Yes, things were easier in those days... bring back the Atari I say !



  • skip0464

    Use flags. Allow the UI to do everything it needs, and set flags to indicate the 'status' of the application.

    However, you have to understand that programming is waaaay different from the olden days. Windows is event based: nothing happens unless some kind of event occurs.

    One other item is that you need to avoid locking up your user interface at all costs. If you have a long running task (for example, a task that needs to be activated when button B is pushed), you can fire off a thread to do so. However, it sounds like your tasks are very short and unobtrusive, so threading is probably not necessary.

    Without fully knowing what you are trying to achieve, have each task set a 'state' variable. Each task will execute when the state variable is a certain value. It'll increment the state at the end. Use a timer with a big case statement (brute force, but may work for a small number of tasks). Something like this:

    Sub Task1
    Do Stuff
    State += 1
    End Sub

    Sub Task2
    DoStuff
    State+=1
    End Sub

    Timer()
    select Case State
    Case 0
    ' Do Nothing: Wait for State to be set
    Case 1
    Call Task1
    Case 2
    Call Task2
    case 3
    State = 0
    End Select
    end sub



  • JohnDurant

    Here's my entire program, with Brendan's suggestion:

    Public Class Form1

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    Dim g As Integer

    For g = 1 To 10

    Application.DoEvents()

    System.Threading.Thread.Sleep(500)

    Label1.Text = g

    Next

    End Sub

    End Class

    When I lowered the sleep time, I realized what the code is doing: It's running the Sleep line all ten times before it gets to the "Label1.Text = g" line. Either that, or it's just not opening the form until all ten pauses are done.

    So this is what I see: after I start, it counts to 5s (500ms * 10) and then opens up the form and puts a "10" in Label1. I assume that it's printing 1 through 10 but it's too fast for me to see, but this may not be the case.

    This is just a trial program I'm writing to understand how to make a pause work. My actual program is a card game where you play against multiple computer opponents. I just want pauses thrown into various places so that I can see the computer's play unfold at a reasonable pace, instead of having five players act instantly.

    How do I make the program stop what it's doing for a second or two, and then continue on where it left off

    It was a piece of cake on my Commodore 64, 20 years ago, for God's sake:

    10 for t = 1 to 600

    20 next t

    Couldn't be any simpler.

    Bob


  • pc-coholic

    I am guessing that you are pressing a button on the form or some other user initiated action is causing this code to run... the problem is that the work being done there is occurring in the main thread of the app, the same thread that is responsible for painting the screen to show your updates to your label text and by sleeping within it you are preventing the visual update.

    In order to get around this problem you’ve got three options, spawn off a new thread to do your work, fire off some work with BackgroundWorker... or DoEvents.

    In your case, the simplest method is to simply use DoEvents which pauses the execution of your code for a moment and lets the window process any outstanding messages... like those to redraw the window with a new value in the label.

    In order to use it in your app we would make only a single change:

    Dim g As Integer

    For g = 1 To 10

    Application.DoEvents() ' Process outstanding messages before sleeping

    System.Threading.Thread.Sleep(4000)

    Label1.Text = g

    Next



  • curwiler

    Bob,

    By the sounds of it, your experience has been with that of a more sequential type of programming language. It was fairly difficult for me when I made the switch to event based programming as well. Later, you learn to design your entire programms differently and they usually come out more efficient. I think that you can do what you are asking though, try the following;

    Public Class Form1

    Dim index As Integer = 0

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    Timer1.Interval = 10

    Timer1.Enabled = True

    End Sub

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick

    Timer1.Interval = 1000

    Select Case index

    Case 0 To 2

    Label1.Text = "Im doing some code"

    Case 3 To 5

    Label1.Text = "Im waiting around"

    Case Else

    Label1.Text = "Im doing some more code"

    End Select

    index += 1

    End Sub

    End Class



  • SomeshChandra

    As we seem to have demonstrated numerous ways to implement a pause I think you need to determine which is most specific to you needs and plump for an approach.

    If you can withstand the application being dead for the delay then thread.sleep will work - if not then a timer approach may work for you.

    Either way I think you have enough choices on here that pitfalls of each have been demonstrated,


  • Zagen

    So some examples of delaying and reasons why some approaches are bad , I would suggest you try them - the examples use a simple form with a couple of buttons on and the final one has a timer control on the form.

    Public Class Form1

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

    Dim g As Integer
    For g = 1 To 10
    System.Threading.Thread.Sleep(1000)
    Label1.Text = g
    Next
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    MsgBox("Hello")
    End Sub
    End Class


    This is bad, a 1 second delay using thread sleep - try clicking the button to start the process and then clicking the second button after the process starts to display the msgbox. The label doesnt update until the end.

    Public Class Form1

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

    Dim g As Integer
    For g = 1 To 10
    Application.DoEvents()
    System.Threading.Thread.Sleep(1000)
    Label1.Text = g
    Next
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    MsgBox("Hello")
    End Sub
    End Class

    This is better as it updates the label and msgbox would respond but lets say I wanted a 10 second delay between loops

    Public Class Form1

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

    Dim g As Integer
    For g = 1 To 10
    Application.DoEvents()
    System.Threading.Thread.Sleep(10000)
    Label1.Text = g
    Next
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    MsgBox("Hello")
    End Sub
    End Class


    Sure the label updates but now you seeing that the UI is unresponsive while it is waiting. Its the self same code as above just with a longer delay.

    If you want a delay but want to keep the UI responsive then one approach may be to use a timer control to achieve a preset delay for the loops whilst making the UI remain responsive.

    Public Class Form1
    Dim g As Integer

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    '//Start Timer
    g = 0
    Timer1.Interval = 10000 'Duration of 10 seconds
    Timer1.Enabled = True
    If g >= 10 Then Timer1.Enabled = False '//Stop on 10th Iteration
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    MsgBox("Hello")
    End Sub

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
    g = g + 1
    Label1.Text = g
    End Sub
    End Class

    So the final solution would enable you to add a long delay but also allow the user interface to remain responsive during this delay. Whne you start it the time will update every 10 seconds but the second button will remain clickable and functional throughout.

    So thread.sleep is not a particularly good solution for items where the program still has to do things during the delay or where the UI needs to remain responsive.

    As for you code - putting it in the form load will never display the label changes as it is in the form load event - this event is run before the form is visible. Hence you would only see the last value present (10) when the form eventually is loaded and becomes visible.

    And the second comment on the C64 code - was that this intentional looping to slow things down. Speed is a great difference you are looking a 1 MHz processor for a C64 as against a even modest spec PC being a 1.5 GHz machine and you are looking at interpreted code on a C64 as against and optimized compiled code in VB.NET

    Things have changed a lot and putting a loop like that to delay yourself - wont work as the compiler will optimize this and modern machines process this extemely quickly, How quickly, put the following code in a button click event and you'll see how quickly it iterates around a loop 1000000 times.

    Dim swatch As New Stopwatch()
    swatch.Start()
    For i = 1 To 1000000
    Next
    swatch.Stop()
    MsgBox(swatch.Elapsed.TotalMilliseconds)



    Hope that gives you a clear indication as to some methods for delaying and why old methods used 20 years ago not longer work today.


  • Ned Ryerson

    PsychUK wrote:

    LOL @ Commadore 64

    Yes, things were easier in those days... bring back the Atari I say !



    I had a Commodore 64 and later a Commodor 128-D. Those were great little machines. I never had an Atari computer. I had an Atari 2600 game console (can you call that a game console ).



  • RemiRenshai

    We're getting there, but it's still not doing what I want. So here's the code in my trial program:

    Public Class Form1

    Dim g As Integer

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    Timer1.Interval = 1000

    Timer1.Enabled = True

    Label2.Text = "count running"

    End Sub

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick

    g = g + 1

    Label1.Text = g

    If g >= 10 Then

    Timer1.Enabled = False

    Label2.Text = "count done"

    End If

    End Sub

    End Class

    What it does is put "count running" in label 2, it counts 10 seconds off in label 1, and then it prints "count done" in label 2 after the 10 seconds.

    Here's the problem - I don't want to see "count running" until the counter is done. In fact, inject 200 lines of code after the --Label2.Text = "count running"-- line. I don't want any of them to execute until the timer is done. I want everything to stop.

    That's what I'm trying to do - I want a line of code in various places in my bigger program that says "OK - EVERYTHING stop where you are for a couple of seconds".

    I guess my confusion lies in the fact that there doesn't seem to be order in the execution of the code. It runs everything simultaneously instead of going:

    Step 1: do this

    Step 2: do this

    Step 3: wait three seconds

    Step 4: do this

    Step...

    Bob


  • Simple Pause