Click here to Skip to main content
15,901,001 members
Articles / Multimedia / GDI+
Article

SQL Server 2005 Circular Progress Bar

Rate me:
Please Sign up or sign in to vote.
4.86/5 (68 votes)
26 Sep 2006CPOL1 min read 267.7K   10.4K   201   77
Shows a spinning progress bar, identical to the SQL Server 2005 busy indicator, without requiring any code.

Sample Image - sql2005circularprogress.jpg

Introduction

After initially searching for the animation used in SQL Server 2005 as an AVI or GIF, I stumbled across the excellent article by Amr Aly Elsehemy, here at The Code Project. Although good code, and indeed a starting point for what I have created, it didn't actually replicate the look and feel of the Microsoft SQL Server 2005 'busy' animation.

At less than 220 lines, I think that this control is pretty compact, and it seems to perform well, even when other threads in my application are busy.

Code

I store each 'segment' of the progress bar in an array, this makes it easy to iterate through later.

VB
Private segmentPaths(11) As Drawing2D.GraphicsPath

The segments are initialized in the CalculateSegments method, which is called when the control is initialized or resized. This method also generates a region which is used to clip the center circle back out when painting the control.

VB
'Create 12 segment pieces
For intCount As Integer = 0 To 11
    secmentPaths(intCount) = New Drawing2D.GraphicsPath

    'We subtract 90 so that the starting segment is at 12 o'clock
    secmentPaths(intCount).AddPie(rctFull, (intCount * 30) - 90, 25)
Next

The ProgressDisk_Paint method is where all the real work goes on (with the exception of the automatic iteration). I think the code speaks for itself, especially the comments :-)

VB
e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
e.Graphics.ExcludeClip(innerBackgroundRegion)

For intCount As Integer = 0 To 11
    If Me.Enabled Then
        If intCount = m_TransitionSegment Then
            'If this segment is the transistion segment, colour it differently
            e.Graphics.FillPath(New SolidBrush(m_TransistionColour), _
                                segmentPaths(intCount))
        ElseIf intCount < m_TransitionSegment Then
            'This segment is behind the transistion segment
            If m_BehindIsActive Then
                'If behind the transistion should be active, 
                'colour it with the active colour
                e.Graphics.FillPath(New SolidBrush(m_ActiveColour),_
                                    segmentPaths(intCount))
            Else
                'If behind the transistion should be in-active, 
                'colour it with the in-active colour
                e.Graphics.FillPath(New SolidBrush(m_InactiveColour), _
                                    segmentPaths(intCount))
            End If
        Else
            'This segment is ahead of the transistion segment
            If m_BehindIsActive Then
                'If behind the the transistion should be active, 
                'colour it with the in-active colour
                e.Graphics.FillPath(New SolidBrush(m_InactiveColour),_
                                    segmentPaths(intCount))
            Else
                'If behind the the transistion should be in-active, 
                'colour it with the active colour
                e.Graphics.FillPath(New SolidBrush(m_ActiveColour),_
                                    segmentPaths(intCount))
            End If
        End If
    Else
        'Draw all segments in in-active colour if not enabled
        e.Graphics.FillPath(New SolidBrush(m_InactiveColour), _
                            segmentPaths(intCount))
    End If
Next
The only other real work is done by the timer increment, which is fired by default every 100ms, but this is exposed as a property.
VB
If m_TransitionSegment = 11 Then
    m_TransitionSegment = 0
    m_BehindIsActive = Not m_BehindIsActive
ElseIf m_TransitionSegment = -1 Then
    m_TransitionSegment = 0
Else
    m_TransitionSegment += 1
End If

Invalidate()

The m_BehindIsActive variable decided whether all the segments behind (anti-clockwise) the transision segment (the segment currently changing colour) should be coloured using the active or inactive colour, both of which are user definable.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect eNate Ltd
United Kingdom United Kingdom
Technical Architect for an expanding software company in the UK. Andrew has spearheaded the development for an internationally used, enterprise-class business process management system built in .Net.

Comments and Discussions

 
GeneralRe: Problem ? Pin
p_rajanikanth1-Feb-07 11:00
p_rajanikanth1-Feb-07 11:00 
GeneralDouble Buffering... [modified] Pin
Daytona_67524-Jul-06 15:04
Daytona_67524-Jul-06 15:04 
GeneralRe: Double Buffering... Pin
ateece2-Oct-06 22:32
ateece2-Oct-06 22:32 
GeneralNot SQL ... it's the Mac OSX Pin
cwilliam24-Jul-06 12:01
cwilliam24-Jul-06 12:01 
GeneralSave image to disk Pin
Jim F. Johnson18-Jul-06 11:08
Jim F. Johnson18-Jul-06 11:08 
AnswerRe: Save image to disk [modified] Pin
ateece18-Jul-06 11:55
ateece18-Jul-06 11:55 
GeneralRe: Save image to disk Pin
VDragon4-Oct-06 8:51
VDragon4-Oct-06 8:51 
GeneralRe: Save image to disk Pin
VDragon4-Oct-06 9:35
VDragon4-Oct-06 9:35 
Here Is The updates Source...
<br />
Imports System.Drawing<br />
Imports System.Windows.Forms<br />
Public Class SpinningProgress<br />
    Private m_InactiveColour As Color = Color.FromArgb(218, 218, 218)<br />
    Private m_ActiveColour As Color = Color.FromArgb(35, 146, 33)<br />
    Private m_TransistionColour As Color = Color.FromArgb(129, 242, 121)<br />
<br />
    Private innerBackgroundRegion As Region<br />
    Private segmentPaths(11) As Drawing2D.GraphicsPath<br />
<br />
    Private m_AutoIncrement As Boolean = True<br />
    Private m_IncrementFrequency As Double = 100<br />
    Private m_BehindIsActive As Boolean = True<br />
    Private m_TransitionSegment As Integer = 0<br />
<br />
    Private WithEvents m_Host As PictureBox<br />
    Private m_Enabled As Boolean<br />
    Private m_SaveFrames As Boolean<br />
    Private m_Frame As Integer<br />
    Private m_BaseFile As String<br />
    Private m_Format As System.Drawing.Imaging.ImageFormat<br />
    Private m_AutoRotateTimer As System.Timers.Timer<br />
<br />
    Property Host() As PictureBox<br />
        Get<br />
            Return m_Host<br />
        End Get<br />
        Set(ByVal value As PictureBox)<br />
            m_Host = value<br />
        End Set<br />
    End Property<br />
<br />
    Property ImageFormat() As System.Drawing.Imaging.ImageFormat<br />
        Get<br />
            Return m_Format<br />
        End Get<br />
        Set(ByVal value As System.Drawing.Imaging.ImageFormat)<br />
            m_Format = value<br />
        End Set<br />
    End Property<br />
<br />
    Property BaseFile() As String<br />
        Get<br />
            Return m_BaseFile<br />
        End Get<br />
        Set(ByVal value As String)<br />
            m_BaseFile = value<br />
        End Set<br />
    End Property<br />
<br />
    Property SaveFrames() As Boolean<br />
        Get<br />
            Return m_SaveFrames<br />
        End Get<br />
        Set(ByVal value As Boolean)<br />
            m_SaveFrames = value<br />
        End Set<br />
    End Property<br />
<br />
    <System.ComponentModel.DefaultValue(GetType(Color), "218, 218, 218")> _<br />
Property InactiveSegmentColour() As Color<br />
        Get<br />
            Return m_InactiveColour<br />
        End Get<br />
        Set(ByVal value As Color)<br />
            m_InactiveColour = value<br />
            m_Host.Invalidate()<br />
        End Set<br />
    End Property<br />
<br />
    <System.ComponentModel.DefaultValue(GetType(Color), "35, 146, 33")> _<br />
    Property ActiveSegmentColour() As Color<br />
        Get<br />
            Return m_ActiveColour<br />
        End Get<br />
        Set(ByVal value As Color)<br />
            m_ActiveColour = value<br />
            m_Host.Invalidate()<br />
        End Set<br />
    End Property<br />
<br />
    <System.ComponentModel.DefaultValue(GetType(Color), "129, 242, 121")> _<br />
    Property TransistionSegmentColour() As Color<br />
        Get<br />
            Return m_TransistionColour<br />
        End Get<br />
        Set(ByVal value As Color)<br />
            m_TransistionColour = value<br />
            m_Host.Invalidate()<br />
        End Set<br />
    End Property<br />
<br />
    <System.ComponentModel.DefaultValue(True)> _<br />
    Property BehindTransistionSegmentIsActive() As Boolean<br />
        Get<br />
            Return m_BehindIsActive<br />
        End Get<br />
        Set(ByVal value As Boolean)<br />
            m_BehindIsActive = value<br />
            m_Host.Invalidate()<br />
        End Set<br />
    End Property<br />
<br />
    <System.ComponentModel.DefaultValue(-1)> _<br />
    Property TransistionSegment() As Integer<br />
        Get<br />
            Return m_TransitionSegment<br />
        End Get<br />
        Set(ByVal value As Integer)<br />
            If value > 11 Or value < -1 Then<br />
                Throw New ArgumentException("TransistionSegment must be between -1 and 11")<br />
            End If<br />
            m_TransitionSegment = value<br />
            m_Host.Invalidate()<br />
        End Set<br />
    End Property<br />
<br />
    <System.ComponentModel.DefaultValue(True)> _<br />
    Property AutoIncrement() As Boolean<br />
        Get<br />
            Return m_AutoIncrement<br />
        End Get<br />
        Set(ByVal value As Boolean)<br />
            m_AutoIncrement = value<br />
<br />
            If value = False AndAlso m_AutoRotateTimer IsNot Nothing Then<br />
                m_AutoRotateTimer.Dispose()<br />
                m_AutoRotateTimer = Nothing<br />
            End If<br />
<br />
            If value = True AndAlso m_AutoRotateTimer Is Nothing Then<br />
                m_AutoRotateTimer = New System.Timers.Timer(m_IncrementFrequency)<br />
                AddHandler m_AutoRotateTimer.Elapsed, AddressOf IncrementTransisionSegment<br />
                m_AutoRotateTimer.Start()<br />
            End If<br />
        End Set<br />
    End Property<br />
<br />
    <System.ComponentModel.DefaultValue(False)> _<br />
    Property Enabled() As Boolean<br />
        Get<br />
            Return m_Enabled<br />
        End Get<br />
        Set(ByVal value As Boolean)<br />
            m_enabled = value<br />
        End Set<br />
    End Property<br />
<br />
    <System.ComponentModel.DefaultValue(CDbl(100))> _<br />
    Property AutoIncrementFrequency() As Double<br />
        Get<br />
            Return m_IncrementFrequency<br />
        End Get<br />
        Set(ByVal value As Double)<br />
            m_IncrementFrequency = value<br />
<br />
            If m_AutoRotateTimer IsNot Nothing Then<br />
                AutoIncrement = False<br />
                AutoIncrement = True<br />
            End If<br />
        End Set<br />
    End Property<br />
<br />
    Public Sub New(ByVal obj As PictureBox)<br />
        ' This call is required by the Windows Form Designer.<br />
        'm_host.InitializeComponent()<br />
        m_Host = obj<br />
        ' Add any initialization after the InitializeComponent() call.<br />
        CalculateSegments()<br />
<br />
        m_AutoRotateTimer = New System.Timers.Timer(m_IncrementFrequency)<br />
        AddHandler m_AutoRotateTimer.Elapsed, AddressOf IncrementTransisionSegment<br />
        m_AutoRotateTimer.Start()<br />
    End Sub<br />
<br />
    Private Sub IncrementTransisionSegment(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs)<br />
        If m_TransitionSegment = 11 Then<br />
            m_TransitionSegment = 0<br />
            m_BehindIsActive = Not m_BehindIsActive<br />
        ElseIf m_TransitionSegment = -1 Then<br />
            m_TransitionSegment = 0<br />
        Else<br />
            m_TransitionSegment += 1<br />
        End If<br />
<br />
        m_Host.Invalidate()<br />
    End Sub<br />
<br />
    Private Sub CalculateSegments()<br />
        Dim rctFull As New Rectangle(0, _<br />
                                     0, _<br />
                                     m_Host.Width, _<br />
                                     m_Host.Height)<br />
        Dim rctInner As New Rectangle(CInt(m_Host.Width * (7 / 30)), _<br />
                                      CInt(m_Host.Height * (7 / 30)), _<br />
                                      CInt(m_Host.Width - (m_Host.Width * (7 / 30) * 2)), _<br />
                                      CInt(m_Host.Height - (m_Host.Height * (7 / 30) * 2)))<br />
        Dim pthInnerBackground As Drawing2D.GraphicsPath<br />
<br />
        'Create 12 segment pieces<br />
        For intCount As Integer = 0 To 11<br />
            segmentPaths(intCount) = New Drawing2D.GraphicsPath<br />
<br />
            'We subtract 90 so that the starting segment is at 12 o'clock<br />
            segmentPaths(intCount).AddPie(rctFull, (intCount * 30) - 90, 25)<br />
        Next<br />
<br />
        'Create the center circle cut-out<br />
        pthInnerBackground = New Drawing2D.GraphicsPath<br />
        pthInnerBackground.AddPie(rctInner, 0, 360)<br />
        innerBackgroundRegion = New Region(pthInnerBackground)<br />
<br />
        If m_SaveFrames = True Then SaveImage()<br />
    End Sub<br />
<br />
    Private Sub SpinningProgress_EnabledChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_Host.EnabledChanged<br />
        If m_enabled = True Then<br />
            If m_AutoRotateTimer IsNot Nothing Then<br />
                m_AutoRotateTimer.Start()<br />
            End If<br />
        Else<br />
            If m_AutoRotateTimer IsNot Nothing Then<br />
                m_AutoRotateTimer.Stop()<br />
            End If<br />
        End If<br />
    End Sub<br />
<br />
    Private Sub ProgressDisk_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles m_Host.Paint<br />
        e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias<br />
        e.Graphics.ExcludeClip(innerBackgroundRegion)<br />
<br />
        For intCount As Integer = 0 To 11<br />
            If m_Host.Enabled Then<br />
                If intCount = m_TransitionSegment Then<br />
                    'If this segment is the transistion segment, colour it differently<br />
                    e.Graphics.FillPath(New SolidBrush(m_TransistionColour), segmentPaths(intCount))<br />
                ElseIf intCount < m_TransitionSegment Then<br />
                    'This segment is behind the transistion segment<br />
                    If m_BehindIsActive Then<br />
                        'If behind the transistion should be active, <br />
                        'colour it with the active colour<br />
                        e.Graphics.FillPath(New SolidBrush(m_ActiveColour), segmentPaths(intCount))<br />
                    Else<br />
                        'If behind the transistion should be in-active, <br />
                        'colour it with the in-active colour<br />
                        e.Graphics.FillPath(New SolidBrush(m_InactiveColour), segmentPaths(intCount))<br />
                    End If<br />
                Else<br />
                    'This segment is ahead of the transistion segment<br />
                    If m_BehindIsActive Then<br />
                        'If behind the the transistion should be active, <br />
                        'colour it with the in-active colour<br />
                        e.Graphics.FillPath(New SolidBrush(m_InactiveColour), segmentPaths(intCount))<br />
                    Else<br />
                        'If behind the the transistion should be in-active, <br />
                        'colour it with the active colour<br />
                        e.Graphics.FillPath(New SolidBrush(m_ActiveColour), segmentPaths(intCount))<br />
                    End If<br />
                End If<br />
            Else<br />
                'Draw all segments in in-active colour if not enabled<br />
                e.Graphics.FillPath(New SolidBrush(m_InactiveColour), segmentPaths(intCount))<br />
            End If<br />
        Next<br />
    End Sub<br />
<br />
    Private Sub ProgressDisk_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_Host.Resize<br />
        CalculateSegments()<br />
    End Sub<br />
<br />
    Private Sub ProgressDisk_SizeChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_Host.SizeChanged<br />
        CalculateSegments()<br />
    End Sub<br />
<br />
    Private Sub SaveImage()<br />
        m_Frame = m_Frame + 1<br />
        m_Host.Image.Save(m_BaseFile & "\Frame" & m_Frame, m_Format)<br />
    End Sub<br />
End Class<br />
<br />

GeneralRe: Save image to disk Pin
ateece5-Oct-06 22:49
ateece5-Oct-06 22:49 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.