Solved

Create a progress bar for timer

Posted on 2014-11-14
4
302 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
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 75

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 86

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

Forrester Webinar: xMatters Delivers 261% ROI

Guest speaker Dean Davison, Forrester Principal Consultant, explains how a Fortune 500 communication company using xMatters found these results: Achieved a 261% ROI, Experienced $753,280 in net present value benefits over 3 years and Reduced MTTR by 91% for tier 1 incidents.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

It’s quite interesting for me as I worked with Excel using vb.net for some time. Here are some topics which I know want to share with others whom this might help. First of all if you are working with Excel then you need to Download the Following …
For those of you who don't follow the news, or just happen to live under rocks, Microsoft Research released a beta SDK (http://www.microsoft.com/en-us/download/details.aspx?id=27876) for the Xbox 360 Kinect. If you don't know what a Kinect is (http:…
Finds all prime numbers in a range requested and places them in a public primes() array. I've demostrated a template size of 30 (2 * 3 * 5) but larger templates can be built such 210  (2 * 3 * 5 * 7) or 2310  (2 * 3 * 5 * 7 * 11). The larger templa…

734 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