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 SubPrivate 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 SubPrivate 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 SubSorry 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.

Program flow - order of execution.
Earl Jr
It works now!
Chandra
A timer calls over and over until you call it's Stop() method.
RUReady
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
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
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..