Edgar Edgar - 2 months ago 19
Vb.net Question

Starting a timer to execute a method every minutes and update a label every 10 secs

Basically what I am trying to do is when the application is running I start a update a stock quote and start a timer every 10 secs (which is 10000 millisecs) it will add 10 to an integer variable the interval is 60 secs and I want a label to display a "next update in" label every 10 second after the minute is reached I want the stock quotes updated and the timer reset to do it over again, and this will always run as long as the program is open.

this is my code so far, it skips the if statement because it isn't at 10 secs when it reaches that statement and exits. should I use a do while loop?

Imports System.Net
Imports System.IO
Imports Newtonsoft.Json


Public Class Form1

Private Symbols As List(Of String) = Nothing
Private Prices() As List(Of String) = Nothing
Private secondCount As Integer
Private intervalCount As Integer = 60
' force Update
Private Sub forceUpdateBtn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles forceUpdateBtn.Click
QuoteUpdater()
End Sub

Public Function GetStockPrices(symbol As String) As List(Of String)
' Dim pricesArray() As String
Dim prices As New List(Of String)()
Dim items() As GoogleFinanceItem

If UCase(symbol) = "INDU" Then
Dim url As String = "http://finance.google.com/finance/info?client=ig&q=INDEXDJX%3A.DJI"
Dim result As String = GetWebResponse(url).Replace("//", "")
' Dim newResult = result.Remove(0, 3)
items = JsonConvert.DeserializeObject(Of GoogleFinanceItem())(result)
' pricesArray = Split(result, ":")
Else
Dim url As String = "http://finance.google.com/finance/info?client=ig&q=" & UCase(symbol)
Dim result As String = GetWebResponse(url).Replace("//", "")
' Dim newResult = result.Remove(0, 3)
items = JsonConvert.DeserializeObject(Of GoogleFinanceItem())(result)
' pricesArray = Split(result, ":")
End If
' pricesArray = Split(pricesArray(4), """")

' prices.Add(CSng(Format(pricesArray(1), "0.00")))
'prices.Add(CSng(Format(pricesArray(1))))
prices.Add(items(0).price)
Return prices

End Function

' Get a web response.
Private Function GetWebResponse(ByVal url As String) As String
' Make a WebClient.
Dim web_client As New WebClient()

' Get the indicated URL.
Dim response As Stream = web_client.OpenRead(url)

' Read the result.
Using stream_reader As New StreamReader(response)
' Get the results.
Dim result As String = stream_reader.ReadToEnd()

' Close the stream reader and its underlying stream.
stream_reader.Close()

' Return the result.
Return result
End Using
End Function

Private Sub FillData()
Dim symbolSubSet() As Control = {Label1, Label2, Label3}
Dim priceSubSet() As Control = {Label4, Label5, Label6}
For i = 0 To 2
symbolSubSet(i).Text = Symbols(i)
priceSubSet(i).Text = Prices(i)(0) 'collection inside a collection. so in the first spot the array is in
Next
statusLbl.Text = "Last Updated: " + Now.ToString
End Sub


Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load, updateTimer.Tick
QuoteUpdater()
updateTimer.Start()

If updateTimer.Interval = 10000 Then
secondCount = secondCount + 10
nextUpdateLbl.Text = "in " + CStr(intervalCount - secondCount) + " secs"
End If

End Sub

Private Sub exitBtn_Click(sender As Object, e As EventArgs) Handles exitBtn.Click
Application.Exit()
End Sub



Private Sub QuoteUpdater()
Me.Cursor = Cursors.WaitCursor

' Get the ticker symbols.
'Dim symbols_text() As String = txtSymbols.Text.Split(","c)
Dim symbols_text() As String = {"PKG", "TEN", "INDU"}
Symbols = New List(Of String)()
For i As Integer = 0 To symbols_text.Length - 1
Symbols.Add(symbols_text(i).Trim())
Next i

' Get the data.
ReDim Prices(0 To Symbols.Count - 1)
For i As Integer = 0 To Symbols.Count - 1
Prices(i) = GetStockPrices(Symbols(i))
Next i

' Graph it.
'DrawGraph()
FillData()
Me.Cursor = Cursors.Default
End Sub



End Class

Answer

The timer interval does not change as time passes, so If updateTimer.Interval = 10000... will always be true unless you change the interval. Since you want to do one thing every 10 secs and another every minute, it just means that you want to do something different ever 6 intervals.

Private Counter As Int32 = 6
Private Sub updateTimer_Tick(... Handles updateTimer.Tick

        Counter += 1
        If Counter < 6 Then
            lblNext.Text = String.Format("Next Update in {0} secs", (6 - Counter) * 10)
            Return
        End If

        ' stuff to do on the minute
        updateTimer.Stop()
        QuoteUpdater()
        lblNext.Text = "Next Update in 1 minute"

        Counter = 1
        updateTimer.Start()
End Sub
Private Sub Form1_Load(...) Handles MyBase.Load
    ' do one time only things like initializing objects and collections
    ...
    lblNext.Text = "First update in 10 secs"
    updateTimer.Interval = 10000
    updateTimer.Enabled = True
End Sub

The code just counts how many intervals have elapsed and does the update when the count gets to 6. After the update, it resets the counter.

I split the FormLoad and Tick events up. By initializing Counter to 6 it allows the first update to happen on the first Tick. This will allow you to do things in FormLoad that only need to be done once. It may also improve how the form looks as it loads the first time since it has time to paint everything before doing quote related stuff.

You also might want to rethink the idea of "Next update in XX secs" since it will say the same thing if there are 1 or 9 secs left. Maybe print the time of the next update?