funkymunkey99
funkymunkey99

Reputation: 3

Countdown Timer with user input

I'm trying to create a countdown timer with user input. Below is the code that just starts a timer of 5 minutes then ends. I want to use something like a Numericupdown to add multiples of 5 minutes, if it is 1 then it's 5 mins, 2 it countsdown from 10 mins etc. I will probably use a second button (button2) to set the time (read from numericupdown, add the minutes then show it on label1) before pressing button1 to start the countdown.

I can't figure out a way of doing it. Do I need to use a For loop?

    Dim TimerEnds As DateTime
    Dim TimerRunning As Boolean

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        If Button1.Text = "Start" Then
            TimerRunning = True
            TimerEnds = DateTime.Now.AddMinutes(5)
            Button1.Text = "Stop"
        Else
            TimerRunning = False
            Button1.Text = "Start"
            Label1.Text = "00:05:00"
        End If
    End Sub

    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
        Dim howLong As TimeSpan = TimerEnds - DateTime.Now
        If TimerRunning Then
            If howLong.TotalMilliseconds > 0 Then
                Label1.Text = howLong.ToString("hh\:mm\:ss")
            Else
                Label1.Text = "Finished"
                TimerRunning = False
            End If
        End If
    End Sub

Upvotes: 0

Views: 228

Answers (1)

jmcilhinney
jmcilhinney

Reputation: 54417

Here's a class that you can use instead of a standard Timer that will remove the need for most of your code:

Public Class CountdownTimer
    Inherits System.Windows.Forms.Timer

    ''' <summary>
    ''' Measures elapsed time.
    ''' </summary>
    Private ReadOnly stopwatch As New Stopwatch

    ''' <summary>
    ''' Indicates whether the <see cref="Expired"/> event has been raised.
    ''' </summary>
    Private expiredRaised As Boolean = False

    ''' <summary>
    ''' Gets or sets the amount of time to count down.
    ''' </summary>
    Public Property Period As TimeSpan

    ''' <summary>
    ''' Gets the amount of time until expiration.
    ''' </summary>
    Public ReadOnly Property Remaining As TimeSpan
        Get
            Return If(stopwatch.Elapsed < Period,
                      Period - stopwatch.Elapsed,
                      TimeSpan.Zero)
        End Get
    End Property

    ''' <summary>
    ''' Gets a value indicating whether the time period has expired.
    ''' </summary>
    Public ReadOnly Property HasExpired As Boolean
        Get
            Return Remaining = TimeSpan.Zero
        End Get
    End Property

    ''' <summary>
    ''' Gets a value indicating whether the timer should stop raising <see cref="Tick"/> events when the period expires.
    ''' </summary>
    ''' <returns></returns>
    Public Property StopOnExpiration As Boolean = True

    ''' <summary>
    ''' Occurs when the period has expired.
    ''' </summary>
    Public Event Expired As EventHandler

    ''' <summary>
    ''' Starts the timer.
    ''' </summary>
    Public Shadows Sub Start()
        MyBase.Start()

        stopwatch.Start()
    End Sub

    ''' <summary>
    ''' Stops the timer.
    ''' </summary>
    Public Shadows Sub [Stop]()
        MyBase.Stop()

        stopwatch.Stop()
    End Sub

    ''' <summary>
    ''' Resets the timer.
    ''' </summary>
    Public Sub Reset()
        stopwatch.Reset()
        expiredRaised = False
    End Sub

    ''' <summary>
    ''' Raises the <see cref="Tick"/> event.
    ''' </summary>
    Protected Overrides Sub OnTick(e As EventArgs)
        'Stop the timer when the period has expired, if configured to do so.
        If HasExpired AndAlso StopOnExpiration Then
            [Stop]()
        End If

        MyBase.OnTick(e)

        'Raise the Expired event once when the period expires.
        If HasExpired AndAlso Not expiredRaised Then
            OnExpired(EventArgs.Empty)
        End If
    End Sub

    ''' <summary>
    ''' Raises the <see cref="Expired"/> event.
    ''' </summary>
    Protected Overridable Sub OnExpired(e As EventArgs)
        'Ensure the Expired event is only raised once, even if the Tick event continues to be raised.
        expiredRaised = True

        RaiseEvent Expired(Me, e)
    End Sub

End Class

You could then use it like this:

Private Sub DisplayTimeRemaining()
    Label1.Text = CountdownTimer1.Remaining.ToString("hh\:mm\:ss")
End Sub

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    If CountdownTimer1.Enabled Then
        CountdownTimer1.Stop()
        CountdownTimer1.Reset()
        Button1.Text = "Start"
    Else
        Button1.Text = "Stop"
        CountdownTimer1.Reset()
        CountdownTimer1.Period = TimeSpan.FromMinutes(NumericUpDown1.Value * 5)
        CountdownTimer1.Start()
    End If

    DisplayTimeRemaining()
End Sub

Private Sub CountdownTimer1_Tick(sender As Object, e As EventArgs) Handles CountdownTimer1.Tick
    DisplayTimeRemaining()
End Sub

Private Sub CountdownTimer1_Expired(sender As Object, e As EventArgs) Handles CountdownTimer1.Expired
    Label1.Text = "Finished"
    Button1.Text = "Start"
End Sub

Upvotes: 1

Related Questions