Solved

Create a progress bar for timer

Posted on 2014-11-14
4
267 Views
Last Modified: 2014-12-17
Hi EE,

In VB.NET, I would like to have on my form a progress bar that decreases.
Lets say I tell the form that the timer is 4 minutes.. I would like the progress abr to decreases to zero at 4mins and it would start Green and going yellow up to red once the timer reaches lets say 3mins or 1/3 left...

can you help me ?

Either a bar or a kind of circle like a clock with a line going clockwise
0
Comment
Question by:PhilippeRenaud
4 Comments
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 40442884
There is a ProgressBar control - put one onto your form.

Have a look at the following:
http://msdn.microsoft.com/en-us/library/system.windows.forms.progressbar.maximum%28v=vs.110%29.aspx

Set the max and minimum values to 240 and 0 (seconds in 4 minutes, try a step of -1 to decrement) then do the PerformStep in your timer event - I assume you wanted a step per second with the above values.
0
 
LVL 74

Accepted Solution

by:
käµfm³d   👽 earned 500 total points
ID: 40443138
I try to avoid referencing other forums if I can help it, but there is a very neat solution on SO (stackoverflow.com/a/9753302/884561, by user1032613) that does exactly what you are seeking--at least in terms of the colors. Adapting the code to VB and combining it with what Andy mentioned, you could have something like:

Imports System.Runtime.InteropServices

Public Class Form1
    Private Const RED As Integer = 2
    Private Const YELLOW As Integer = 3
    Private Const GREEN As Integer = 1

    <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=False)> _
    Public Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal w As IntPtr, ByVal l As IntPtr) As IntPtr
    End Function

    Public Sub SetState(ByVal pBar As ProgressBar, ByVal state As Integer)
        SendMessage(pBar.Handle, 1040, New IntPtr(state), IntPtr.Zero)
    End Sub

    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
        Dim currentPercentage As Double

        Me.ProgressBar1.PerformStep()

        currentPercentage = (Me.ProgressBar1.Value / Me.ProgressBar1.Maximum)

        If currentPercentage < 0.25 Then
            SetState(Me.ProgressBar1, RED)
        ElseIf currentPercentage < 0.75 Then
            SetState(Me.ProgressBar1, YELLOW)
        ElseIf currentPercentage <= 0 Then
            Me.Timer1.Enabled = False
        End If

    End Sub
End Class

Open in new window


To yield:

 Screenshot
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 40443225
This is pared down and modified code from my "Kids Alarm Clock" project, which I demonstrate here:
https://www.youtube.com/watch?v=qucWOkZp0Uw
Full Source Code:
http://dl.dropbox.com/u/5131616/KidAlarmClockProject%28Source%29.zip

Obviously this doesn't do exactly what you described, but I thought you might be interested in the parts of the code that draw the circular portions.  They represent how much time is left until the alarm goes off.  The outer red band is how many hours are left.  The middle blue band is how many minutes is left.  The inner green band is how many seconds are left.  In this image, there is 5 hours, 36 minutes, and 15 seconds left:
5 hours, 36 minutes, 15 seconds left
CircularCountdownTimer UserControl:
Public Class CircularCountdownTimer

    Private Const OuterHourDistance As Double = 0.98
    Private Const InnerHourDistance As Double = 0.78

    Private Const OuterMinuteDistance As Double = 0.68
    Private Const InnerMinuteDistance As Double = 0.48

    Private Const OuterSecondDistance As Double = 0.38
    Private Const InnerSecondDistance As Double = 0.18

    ' The Target Time to stop at:
    Private _StopHour As Integer ' 0 to 23
    Private _StopMinute As Integer ' 0 to 59
    Private _StopSecond As Integer ' ' 0 to 59

    Private ReadOnly Property Time() As TimeSpan
        Get
            Return New TimeSpan(Me._StopHour, Me._StopMinute, Me._StopSecond)
        End Get
    End Property

    Public Sub SetDuration(ByVal TS As TimeSpan)
        Dim StopTime As DateTime = DateTime.Now.Add(TS)
        _StopHour = StopTime.TimeOfDay.Hours
        _StopMinute = StopTime.TimeOfDay.Minutes
        _StopSecond = StopTime.TimeOfDay.Seconds
        Me.Refresh()
    End Sub

    Private WithEvents Tmr As System.Windows.Forms.Timer

    Private Sub CircularCountdownTimer_Load(sender As Object, e As EventArgs) Handles Me.Load
        ' Double Buffered to reduce flicker
        Me.SetStyle(ControlStyles.UserPaint, True)
        Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
        Me.SetStyle(ControlStyles.DoubleBuffer, True)
        Me.SetStyle(ControlStyles.ResizeRedraw, True)
        Me.UpdateStyles()

        Tmr = New System.Windows.Forms.Timer
        Tmr.Interval = 1000
        Tmr.Enabled = True
    End Sub

    Private Sub Tmr_Tick(sender As Object, e As EventArgs) Handles Tmr.Tick
        Me.Refresh()
    End Sub

    Private Sub CircularCountdownTimer_Resize(sender As Object, e As EventArgs) Handles Me.Resize
        Me.Refresh()
    End Sub

    Private Sub CircularCountdownTimer_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
        Dim C As Color
        Dim cx As Single = Me.Width / 2
        Dim cy As Single = Me.Height / 2
        Dim SmallerDimension = Math.Min(Me.Width, Me.Height)
        Dim innerDistance, outerDistance As Single

        Static hourList As New List(Of Point)
        Static prevHour As Integer = -1
        Static minList As New List(Of Point)
        Static prevMin As Integer = -1
        Static secList As New List(Of Point)
        Static prevSec As Integer = -1

        Dim ts As TimeSpan = Me.CalcKillTime.Subtract(DateTime.Now)
        Dim startAngle As Integer = GetHourAngle(12)
        Dim stopAngle As Integer
        Dim ps() As Point

        If ts.Hours >= 1 Then
            C = Color.Red
            stopAngle = GetMinuteAngle(ts.Hours * 5)
            If stopAngle <> prevHour Then
                outerDistance = SmallerDimension * OuterHourDistance / 2
                innerDistance = SmallerDimension * InnerHourDistance / 2
                BuildTimeSlice(hourList, cx, cy, stopAngle, innerDistance, outerDistance)
                prevHour = stopAngle
            End If
            ps = hourList.ToArray
            Using hb As New Drawing2D.HatchBrush(Drawing2D.HatchStyle.Percent10, Color.Black, C)
                e.Graphics.FillPolygon(hb, ps)
            End Using
            e.Graphics.DrawLines(Pens.Black, ps)
        End If
        If ts.Minutes > 0 Then
            C = Color.Blue
            stopAngle = GetMinuteAngle(ts.Minutes)
            If stopAngle <> prevMin Then
                outerDistance = SmallerDimension * OuterMinuteDistance / 2
                innerDistance = SmallerDimension * InnerMinuteDistance / 2
                BuildTimeSlice(minList, cx, cy, stopAngle, innerDistance, outerDistance)
                prevHour = stopAngle
            End If
            ps = minList.ToArray
            Using hb As New Drawing2D.HatchBrush(Drawing2D.HatchStyle.Percent10, Color.Black, C)
                e.Graphics.FillPolygon(hb, ps)
            End Using
            e.Graphics.DrawLines(Pens.Black, ps)
        End If
        If ts.Seconds > 0 Then
            C = Color.LightGreen
            stopAngle = GetMinuteAngle(ts.Seconds)
            If stopAngle <> prevMin Then
                outerDistance = SmallerDimension * OuterSecondDistance / 2
                innerDistance = SmallerDimension * InnerSecondDistance / 2
                BuildTimeSlice(secList, cx, cy, stopAngle, innerDistance, outerDistance)
                prevHour = stopAngle
            End If
            ps = secList.ToArray
            Using hb As New Drawing2D.HatchBrush(Drawing2D.HatchStyle.Percent10, Color.Black, C)
                e.Graphics.FillPolygon(hb, ps)
            End Using
            e.Graphics.DrawLines(Pens.Black, ps)
        End If
    End Sub

    Private Sub BuildTimeSlice(ByVal pList As List(Of Point), _
                               ByVal cx As Single, ByVal cy As Single, ByVal MinuteAngle As Integer, _
                               ByVal innerDistance As Single, ByVal outerDistance As Single)
        pList.Clear()
        pList.Add(GetPoint(cx, cy, 360, outerDistance))
        For i As Integer = 360 To MinuteAngle Step -6
            pList.Add(GetPoint(cx, cy, i, outerDistance))
            If i Mod 30 = 0 Then
                pList.Add(GetPoint(cx, cy, i, innerDistance))
                pList.Add(GetPoint(cx, cy, i, outerDistance))
            End If
        Next
        pList.Add(GetPoint(cx, cy, MinuteAngle, innerDistance))
        For i As Integer = MinuteAngle To 360 Step 6
            pList.Add(GetPoint(cx, cy, i, innerDistance))
        Next
        pList.Add(GetPoint(cx, cy, 360, outerDistance))
    End Sub

    Private Function GetHourAngle(ByVal hour As Integer) As Integer
        hour = IIf(hour = 0, 12, IIf(hour <= 12, hour, hour - 12))
        Return (-hour + 12) * 30
    End Function

    Private Function GetMinuteAngle(ByVal minute As Integer) As Integer
        Return -6 * (minute - 60)
    End Function

    Private Function GetPoint(ByVal cx As Single, ByVal cy As Single, ByVal angleInDegrees As Single, ByVal distance As Single) As Point
        ' angleInDegrees
        ' Valid values are 0 --> 359 (six degrees = one minute on clock)
        ' draw a line from the center of the circle:
        ' 0 = up
        ' 90 = left
        ' 180 = down
        ' 270 = right

        ' Offset and Invert Angle then Convert Degrees to Radians
        angleInDegrees = -(angleInDegrees + 90) * Math.PI / 180

        ' Compute the point that is at the specified angle from horizontal and at the specifed distance
        Return New Point(cx + distance * Math.Cos(angleInDegrees), cy + distance * Math.Sin(angleInDegrees))
    End Function

    Public Function CalcKillTime() As DateTime
        Dim AM As Boolean = DateTime.Now.Hour < 12
        Dim ts As TimeSpan = Me.Time
        If AM Then
            If DateTime.Now.Hour = 0 AndAlso Me.Time.Hours = 12 Then
                If DateTime.Now.Minute < ts.Minutes Then
                    Return DateTime.Today.AddMinutes(ts.Minutes)
                End If
            ElseIf ts < DateTime.Now.TimeOfDay Then
                ts = ts.Add(New TimeSpan(12, 0, 0))
            End If
            Return DateTime.Today.Add(ts)
        Else
            If ts.Hours = 12 Then
                If DateTime.Now.Hour = 12 Then
                    If ts > DateTime.Now.TimeOfDay Then
                        Return DateTime.Today.Add(ts)
                    End If
                End If
                Return DateTime.Today.AddDays(1).AddMinutes(ts.Minutes)
            Else
                ts = New TimeSpan(ts.Hours + 12, ts.Minutes, 0)
                If ts > DateTime.Now.TimeOfDay Then
                    Return DateTime.Today.Add(ts)
                Else
                    Return DateTime.Today.AddDays(1).Add(New TimeSpan(ts.Hours - 12, ts.Minutes, 0))
                End If
            End If
        End If
    End Function

End Class

Open in new window

0
 
LVL 1

Author Closing Comment

by:PhilippeRenaud
ID: 40504919
Hi sorry for the long wait,
Thanks this is perfect
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Suggested Solutions

This article describes relatively difficult and non-obvious issues that are likely to arise when creating COM class in Visual Studio and deploying it by professional MSI-authoring tools. It is assumed that the reader is already familiar with the cla…
Creating an analog clock UserControl seems fairly straight forward.  It is, after all, essentially just a circle with several lines in it!  Two common approaches for rendering an analog clock typically involve either manually calculating points with…
It is a freely distributed piece of software for such tasks as photo retouching, image composition and image authoring. It works on many operating systems, in many languages.
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now