Program flow - order of execution.

As a real novice I am writing a small application to measure a persons reaction time by presenting a prompt on screen and then measuring how long before a key is pressed.

My problem is understanding the program flow. When run the form is presented and then when the Start button is pressed there is a short, random delay and the prompt presented. The clock stops when any key is pressed (sub EndTimer) and the time presented - all as expected - but then the prompt is presented again and again and again..... The app works as intended except for the cycling. I do not understand why it is looping. The relavant code follows. I thought it would run through the 2 calls capture the keypress and then stop at the btnStart_Click End Sub.

Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _

Handles btnStart.Click

Call RandomDelay(1, 2)

Call PromptAndStartTimer()

End Sub

Private Sub RandomDelay(ByVal MinSeconds As Integer, ByVal MaxSeconds As Integer)

Dim Cycles As Double

Dim Pause As Integer

Cycles = (CInt(Int((MaxSeconds * Rnd()) + MinSeconds)))

' Capture milliseconds system been running

Pause = My.Computer.Clock.TickCount

' Waste time for between 1 & 6 seconds

Do While (My.Computer.Clock.TickCount - Pause) < (Cycles * 1000)

Loop

End Sub

Private Sub PromptAndStartTimer()

' QueryPerformanceCounter and QueryPerformanceFrequency.

' Use to provide a high resolution clock.

' Capture Frequecy of Tick in Ticks/second

Call QueryPerformanceFrequency(Frequency)

' Capture StartTick number

Call QueryPerformanceCounter(StartTick)

' and present prompt

tbxPrompt.Text = "Press any letter key now"

End Sub

Private Sub EndTimer(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyEventArgs) _Handles btnStart.KeyDown

'Capture EndTick number

Call QueryPerformanceCounter(EndTick)

' Calculate reaction time

tbxTime.Text = (EndTick - StartTick) / Frequency

tbxPrompt.Text = " "

End Sub

Sorry for such a long post but I wanted to be sure I provided enough information. I have tried looking all over the place for help but have come up with nothing - I am probably not using the right search terms.

Very many thanks in advance for any pointers. Peter.



Answer this question

Program flow - order of execution.

  • Earl Jr

    Thank you!
    It works now!



  • Chandra

    A timer calls over and over until you call it's Stop() method.



  • RUReady

    There is a nice stopwatch class in the new framework - easy to use...

  • I.F. Kruzenshtern

    Sorry, I missed that. You may find your answer here:

    http://msdn.microsoft.com/library/default.asp url=/library/en-us/dnpag/html/scalenethowto09.asp

    as this is sample code that uses those APIs from .NET.



  • Fernando Stockler

    Many thanks for such a quick reply.

    Please may I ask you to expand a little on what you have said Are you talking about the
    Call QueryPerformanceCounter(EndTick) line I thought I was reading a system variable not starting a timer. Just in case it matters here are the function declarations.

    Private Declare Function QueryPerformanceCounter Lib "kernel32" _
    (ByRef pcTickCount As Long) As Integer

    Private Declare Function QueryPerformanceFrequency Lib "kernel32" _
    (ByRef pcFrequency As Long) As Integer

    Thanks, Peter


  • Pramod

    Well, I have tried that code,
    but I seem to have an overflow error..

    Private Sub inbox_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles Inbox.KeyPress

    Result = (Now.Ticks - StartInterval) / 10000

    tmr.Stop()

    tb.Visible = False

    Inbox.Text = "Response Latency: " & Result & " Milliseconds."

    Inbox.ReadOnly = True

    e.Handled = True

    End Sub


    it says that its an overflow...
    This only occurs when I press a key in the text box, just like said in the
    Sub inbox_KeyPress...
    but why does it happen to be an overflow
    How can I fix it

    Thank You
    Keehun Nam


  • Terry Field

    Wow! Such quick repiles. Many thanks to you all especially ReneeC for taking the time to write a much more elegant piece of code. I will study it and understand it as soon as I can.

    As you realise this is part of my learning exercise and, while I will use ReneeC's approach, I would like to try and understand why my effort behaves as it does. So I wonder if someone would be prepared to have a go at explaining where I have gone wrong. It's not just a case of solving this problem but of understanding things a bit better.

    Once again thanks for the replies and your forebearance with a real novice.

    Peter.


  • JpFortin

     

    I apologize but there are some usages, that are difficult for me. This program should be TOTALLY event driven.

    So I've written a little something. All controls are totally dynamic. Take a clean fresh project and open the editor.

    Cntrl-A

    Delete  - clean the form out totally and then cut and paste this in it and enjoy....

    There is NO looping and no waiting on anything.

     

     

    Imports system

    Imports system.math

    Public Class Form1

        Protected Friend WithEvents tb As New TextBox

        Protected Friend WithEvents tmr As New Timer

        Protected Friend WithEvents Inbox As New TextBox

        Protected Friend WithEvents cbGo As New Button

        Protected Friend WithEvents cbExit As New Button

        Protected Friend WithEvents cbReset As New Button

        Protected generator As New Random

        Protected StartInterval As New Long

        Protected Result As UInt32

     

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

            init()

            Randomize()

        End Sub

        Private Sub tmr_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles tmr.Tick

            tmr.Stop()

            Inbox.Focus()

            tb.Visible = True

            StartInterval = Now.Ticks

        End Sub

     

        Private Sub inbox_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles Inbox.KeyPress

            Result = (Now.Ticks - StartInterval) / 10000

            tmr.Stop()

            tb.Visible = False

            Inbox.Text = "Response Latency: " & Result & " Milliseconds."

            Inbox.ReadOnly = True

            e.Handled = True

        End Sub

     

        Private Sub cbGo_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles cbGo.Click

            tb.Visible = False

            cbGo.Enabled = False

            Inbox.Clear()

            tmr.Interval = RandomInterval()

            tmr.Start()

        End Sub

     

        Private Sub cbReset_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles cbReset.Click

            tmr.Stop()

            tb.Visible = False

            cbGo.Enabled = True

            Inbox.ReadOnly = False

            Inbox.Clear()

        End Sub

        Private Function RandomInterval() As Integer

            Const MinInt As Integer = 5000 ' 5 Seconds

            Const MaxInt As Integer = 30000 ' 30 seconds

            Return generator.Next(MinInt, MaxInt)

        End Function

       

        Private Sub init()

            'Set the controls up dynamically

            Const MeSize As Integer = 300

            Const tbsize As Integer = 30

            Const CntrlRight As Integer = 20

            Dim diff = ((Sqrt((MeSize ^ 2) * 2) - Sqrt((tbsize ^ 2)) * 2) / 2) * 0.707 ' centering

            tb.Size = New Size(tbsize, tbsize)

            tb.BackColor = Color.Teal

            tb.Visible = False

            Me.Size = New Size(MeSize, MeSize + 30)

            Me.Controls.Add(tb)

            tb.Location = New Point(diff, diff)

            cbGo.Text = "Go"

            Me.Controls.Add(cbGo)

            cbGo.Location = New Point(CntrlRight, MeSize - 30)

            cbGo.Width -= 30

            cbExit.Text = "Exit"

            Me.Controls.Add(cbExit)

            cbExit.Size = cbGo.Size

            cbExit.Location = New Point(MeSize - 60, cbGo.Top)

            Me.Controls.Add(Inbox)

            Inbox.AcceptsReturn = True

            Inbox.Location = New Point(CntrlRight, cbGo.Top - Inbox.Height - 10)

            Inbox.Width = MeSize - ((CntrlRight * 2) + 8)

            Me.Controls.Add(cbReset)

            cbReset.Size = cbExit.Size

            cbReset.Text = "Reset"

            cbReset.Location = New Point(cbExit.Left - 50, cbExit.Top)

            tmr.Enabled = True

            tmr.Stop()

        End Sub

       

        Private Sub cbExit_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles cbExit.Click

            Me.Close()

        End Sub

    End Class

     

     



  • darc

    Change this

    Protected Result As UInt32

    to this

    Protected Result As Long



  • ChristoRaja

    Peter,

    I hope you do learn from what I wrote.

    I believe you program behaves the way it does is what cgraus said, timers are retitiive until stopped. You'll notice that in my code I'm really meticulous about instantly stopping the timer, until I explicity want it to run..



  • Program flow - order of execution.