Solitaire


I know how to do it using Sleep, but can't figure out how it would work with the Timer control. I have a large application that "flips" digits in textboxes casino style, using the Sleep method. All the code for that procedure is in a button click event. However, if the user decides to click on a different button (to reset, or exit, etc.) it needs to wait for all the digits to finish flipping first.

Here is some simple code I tried in a test program. The timer code doesn't work. It instantly displays the 9. The Sleep method does work. I have the Timer1.Interval set to 500.

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

Timer1.Enabled = True

For x As Integer = 1 To 9

TextBox1.Text = x.ToString

Timer1.Start()

TextBox1.Refresh()

Timer1.Stop()

Next

Timer1.Enabled = False

For x As Integer = 1 To 9

TextBox1.Text = x.ToString

System.Threading.Thread.Sleep(500)

TextBox1.Refresh()

Next

End Sub




Re: How do you add a pause with the Timer control? How about using two timers?

element109


Code Snippet

Public Class Form1

Dim x As Integer

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

Timer1.Interval = 1000 'One Second

End Sub

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

Timer1.Enabled = True 'Start the timer

End Sub

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

Timer1.Enabled = False 'Stop the timer

End Sub

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

x += 1

If x = 10 Then

x = 1

End If

TextBox1.Text = x.ToString

End Sub

End Class





Re: How do you add a pause with the Timer control? How about using two timers?

Spidermans_DarkSide - VSIP

Hiya,

Try this and watch the time when it gets to zero seconds.

This shows the Date and Time from NOW in the Form title bar.

It stops for 10 seconds and then restarts showing the Now time again.

It uses the Timer2 tick event to start and stop the timer Timer1.

Regards,

S_DS

____________________________________________

This project only uses two timers.

Public Class Form1

' Set the interval to 1000 milliseconds = 1 second

' within each Timer control.

' ENABLE the timers.

Private Sub Form1_Load(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles MyBase.Load

Timer1.Interval = 1000

Timer1.Enabled = True

Timer2.Interval = 1000

Timer2.Enabled = True

End Sub

Private Sub Timer1_Tick(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles Timer1.Tick

' Show the date and time in the FORM title bar!!

Me.Text = Now.ToLongDateString & " " & Now.ToLongTimeString

End Sub

Private Sub Timer2_Tick(ByVal sender As Object, _

ByVal e As System.EventArgs) Handles Timer2.Tick

' Here is a pause for 10 seconds.

If Now.Second = 0 Then Timer1.Stop()

If Now.Second = 10 Then Timer1.Start()

End Sub

End Class







Re: How do you add a pause with the Timer control? How about using two timers?

Solitaire

Sorry, that doesn't help.

I need something as simple as the code I posted above. It needs to be placed in the button click event, and it will be repeated dozens of times for split seconds each time as the textbox keeps refreshing. Other pauses with varying times (fractions of a second) will also be used in the same event to separate each of 8 textboxes, (which I set up as an array of textboxes in a separate sub). As you can see, every statement using System.Threading.Thread.Sleep should be replaced with a pause using a Timer instruction, but as simply and clearly as possible!

Here is part of the actual code I'm using now. It works perfectly except that the user cannot interrupt the process to select another event.

Private Sub btnNext_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnNext.Click

Dim winner, L, idig, Q, R As Integer

Dim swin, dig As String

' ' ' Note: Some code omited here -- Some variables were declared at class-level

winner = shuffle(win)

swin = winner.ToString

L = N - swin.Length

swin = StrDup(L, "0") & swin

win = win + 1

If flash = False Then 'show winning number instantly

' ' ' Code omitted since it doesn't use a pause

Else

If win = 1 Then

lblWait.Text = "Always wait for flash to stop before clicking Next or another button."

lblWait.Refresh()

System.Threading.Thread.Sleep(100)

End If

For x As Integer = 1 To 8 'clear previous winning number

TextArray(x).Clear()

TextArray(x).Refresh()

Next x

System.Threading.Thread.Sleep(200) 'pause before next number

lblIndex.ForeColor = Color.FromArgb(130, 130, 130)

lblIndex.Text = win.ToString 'winner count in gray

lblIndex.Refresh()

Q = N

If P > 0 Then 'don't flip inactive digits

For x As Integer = N To N - P Step -1

dig = swin.Substring((N - x), 1)

TextArray(x).ForeColor = Color.FromArgb(120, 120, 120)

TextArray(x).Text = dig

TextArray(x).Refresh()

System.Threading.Thread.Sleep(200)

Q = N - P 'active digits

Next x

End If

For x As Integer = Q To 1 Step -1 'flip winning number digits

dig = swin.Substring(N - x, 1)

idig = Convert.ToInt32(dig)

For y As Integer = 0 To 9 'first flip from 0 to 9

TextArray(x).ForeColor = Color.Black

TextArray(x).Text = y.ToString

TextArray(x).Refresh()

System.Threading.Thread.Sleep(90)

Next

For y As Integer = 0 To idig 'then flip from 0 to value

TextArray(x).Text = y.ToString

TextArray(x).Refresh()

System.Threading.Thread.Sleep(90)

Next y

System.Threading.Thread.Sleep(90)

Next x

lblIndex.ForeColor = Color.Black 'winner count in black after flip finishes

lblIndex.Refresh()

For y As Integer = 1 To 7 'flash winning number in gold

If y Mod 2 = 0 Then R = N Else R = Q

For x As Integer = 1 To R 'alternate active with all digits

TextArray(x).BackColor = Color.Gold

Next x

For x As Integer = 1 To N

TextArray(x).Refresh()

Next x

System.Threading.Thread.Sleep(200)

For x As Integer = 1 To N 'original color

TextArray(x).BackColor = Color.FromArgb(255, 255, 192)

Next x

For x As Integer = 1 To N

TextArray(x).Refresh()

Next x

System.Threading.Thread.Sleep(90)

Next y

lblWait.Text = ""

End If

End Sub






Re: How do you add a pause with the Timer control? How about using two timers?

element109

Timer1.Enabled = True

While Timer1.Enabled

'Wait

End While

In your timer tick event sent the timer enabled to false.





Re: How do you add a pause with the Timer control? How about using two timers?

JohnWein

This should accomplish the same result as Sleep(500) without locking the thread.

Code Snippet

Dim Cnt As Int32

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

Timer1.Interval = 500

Cnt = 1

Timer1.Start()

End Sub

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

Timer1.Stop()

TextBox1.Text = CStr(Cnt)

If Cnt = 9 Then Return

Cnt += 1

Timer1.Start()

End Sub





Re: How do you add a pause with the Timer control? How about using two timers?

element109

That's the same as my original post.



Re: How do you add a pause with the Timer control? How about using two timers?

JohnWein

Using a timer is definitely different than using Sleep. Sleep is inline while I use Subs with a timer. Here is how I would approach the beginning of your code using a timer:

Code Snippet

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

If flash = False Then 'show winning number instantly

' ' ' Code omitted since it doesn't use a pause

Return

End If

If win = 1 Then

lblWait.Text = "Always wait for flash to stop before clicking Next or another button."

Timer1.Interval = 100

Timer1.Tag = "Step2"

Timer1.Start()

End If

End Sub

Private Sub Step2()

For x As Integer = 1 To 8 'clear previous winning number

TextArray(x).Clear()

Next x

Timer1.Interval = 200

Timer1.Tag = "Step3"

Timer1.Start()

End Sub

Private Sub Step3()

If P <= 0 Then 'flip inactive digits

Timer1.Tag = "Step5"

Else

Timer1.Tag = "Step4"

End If

Timer1.Interval = 20

Timer1.Start()

End Sub

Private Sub Step4()

Static X As Integer

Static InStep4 As Boolean

If InStep4 Then

X -= 1

Else

InStep4 = True

X = N

End If

dig = swin.Substring((N - X), 1)

TextArray(X).ForeColor = Color.FromArgb(120, 120, 120)

TextArray(X).Text = dig

Q = N - P 'active digits

If X > N - P Then

Timer1.Interval = 200

Else

Timer1.Interval = 20

Timer1.Tag = "Step5"

InStep4 = False

End If

Timer1.Start()

End Sub

Private Sub Step5()

'continue with the Subs

End Sub

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

Timer1.Stop()

CallByName(Me, Timer1.Tag.ToString, CallType.Method)

End Sub

This is not real code. It is only to show an approach. I have simply cut an pasted your code into Subs.





Re: How do you add a pause with the Timer control? How about using two timers?

Spidermans_DarkSide - VSIP

Hi,

Try this then instead.

It uses the system time ticks value ( apparently 1 tick is 100 nanoseconds or 1 * 10 ^ -7 or 0.0000001 of a second ).

Add one button and one richTextBox to a FORM to try this one out.

Use a value of 5 million ( 5000000 ) for half a second.

It does not use a Timer nor does it force the thread to Sleep.

Comment out or delete the highlighted line to see the difference.

Hope you like it

Regards,

S_DS

________________________________

Public Class Form1

Private Sub Pause(ByVal pauseValue As Long)

'Sets myInterval to the time RIGHT NOW!!

Dim myInterval As Date = Now()

'Keeps checking the time NOW to see if this Pause Subs

' pauseValue has elapsed

Do

If Now.Ticks - myInterval.Ticks >= pauseValue Then

'Exit the Sub once the pauseValue has elapsed.

Exit Sub

End If

Loop

End Sub

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

For count As Integer = 0 To 100

RichTextBox1.AppendText(count.ToString & vbNewLine)

RichTextBox1.Refresh()

' 10,000,000 ticks is 1 second.

Pause(10000000)

Next

End Sub

End Class






Re: How do you add a pause with the Timer control? How about using two timers?

SJWhiteley

SDS, that makes no difference: the application would be what is referred to as 'compute bound': the application will effectively lock up until the Do-Loop has completed - no better than sleep.

You have to use the timer to continue to have the application responsive, and act predictably.

(The posts from Element and John are pretty close, so I won't add my way of doing it.)






Re: How do you add a pause with the Timer control? How about using two timers?

Solitaire

I won't get a chance to try any of your suggestions until much later tonight, but most of the suggestions I saw are much too involved.

Meanwhile, I thought of substituting a subprocedure to be called using the same argument as I used for the Sleep method. The sub would then pause for the specified number of miniseconds.

In QBasic, this is accomplished easily with this code:

pause = 1.5
t = TIMER
DO WHILE t + pause >= TIMER
LOOP

It uses an integer value which keeps changing every second. Is there anything comparable in .NET that can be used similarly


What I was originally thinking of was to set the Timer to the specified interval and have it run for a single interval, and then stop. Is this possible

What about the TimeSpan method that was mentioned in one of my books How can that be implemented to an interval of time to be used in a loop


And what about adding DoEvents to the code before using Sleep






Re: How do you add a pause with the Timer control? How about using two timers?

SJWhiteley

Solitaire wrote:


And what about adding DoEvents to the code before using Sleep

What will that gain you Remember, each time sleep is active, your application will be unresponsive - the do events will only handle any outstanding events. Honestly, If you have to resort to Do Events you are doing something seriously wrong.

It's one of those things which is a legacy from VB6, which needed a helping hand, occasionally. (think of DoEvents as Hot Pink Duct Tape with the sticky almost gone...)

Run your timer, in the timer event check a state. If a time interval has passed, increase the state and based on that state perform an action (an action could be to disable the timer). In your other events (buttons, etc), if the timer is enabled, then don't do anything.






Re: How do you add a pause with the Timer control? How about using two timers?

JohnWein

Using a timer requires a different thought process than using sleep. With a timer you exit all Subs and wait for input. With Sleep you stop all processing and ignore any input. It's the difference between step-by-step inline processing and event driven processing. Your QBasic idea doesn't gain anything. Instead of going to Sleep you are doing useless processing. You are still ignoring input. If you absolutely have to have a direct responsive replacement for Sleep this will work

Code Snippet

Sub DelayWithResponse(ByVal TimeToPause As TimeSpan)

Dim StartTime As DateTime = Now

Do While (Now - StartTime) < TimeToPause

Application.DoEvents()

Loop

End Sub

I personally don't like using DoEvents because I have had bad expierences with it in the past. But then I don't like Sleep at all.





Re: How do you add a pause with the Timer control? How about using two timers?

Solitaire

Thanks, guys, for your help. I'm going to keep working at it and eventually may come up with a satisfactory solution.






Re: How do you add a pause with the Timer control? How about using two timers?

Solitaire

I just tried Spiderman's approach and I like it!

However, upon further testing, it works just the same as Sleep unless DoEvents is added. Then it's similar to JohnWein's solution.

Private Sub Button7_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button7.Click

'same as Sleep, cannot be stopped unless DoEvents is added to sub

For x As Integer = 1 To 9

TextBox1.Text = x.ToString

TextBox1.Refresh()

' 10,000,000 ticks is 1 second.

Call Pause(5000000)

Next x

TextBox1.Clear()

End Sub

Private Sub Pause(ByVal pauseValue As Long)

'Sets myInterval to the time RIGHT NOW!!

Dim myInterval As Date = Now()

'Keeps checking the time NOW to see if pauseValue has elapsed

Do

Application.DoEvents() 'will not execute another event until done

Loop While Now.Ticks - myInterval.Ticks <= pauseValue

End Sub