Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / multimedia / GDI+

Bar chart in DataGridView

4.79/5 (40 votes)
24 Aug 2010CPOL 91.8K   4.5K  
How to show a bar chart in a DataGridView
Image 1

Introduction

Sometimes it's useful to graphically show the value of a column in a DataGridView so the user can compare rows easily. This is an example of implementing this on any DataGridView by only calling a shared class method from the DataGridView's CellPainting event, as I've described in my blog http://ensamblareficiente.blogspot.com (Spanish).

Using the Code

The project shows, in a simple manner, how to get the screenshot's grid working.

This is the method calling based on if we want to show the target indicator or not (the CheckBox1 state tells us this):

VB.NET
Private Sub DataGridView1_CellPainting(ByVal sender As Object, _
        ByVal e As System.Windows.Forms.DataGridViewCellPaintingEventArgs) _
        Handles DataGridView1.CellPainting
    '   Avoids rows or columns out of data area
    If e.RowIndex < 0 OrElse e.ColumnIndex < 0 Then Exit Sub

    '   Checks if it's painting percent column
    If e.ColumnIndex <> Columns.Percent Then Exit Sub

    '   Get data row
    Dim oRow As DataSet1.DataRow = _
        DirectCast(DataGridView1.Rows(e.RowIndex).DataBoundItem, DataRowView).Row

    '   Tells to DataGridView that we will take care of painting cell
    e.Handled = True

    '   Selects bar color based on percent value.
    Dim oColor As Drawing.Color = Color.Green
    If CheckBox1.Checked AndAlso oRow.percent < _ciTarget Then oColor = Color.Red

    '   Draws cell with bar
    If CheckBox1.Checked Then
        Bar.PintaDegradado(oColor, e, oRow.percent, _ciTarget, Color.Orange)
    Else
        Bar.PintaDegradado(oColor, e, oRow.percent)
    End If
End Sub

This is the bar class code:

VB.NET
''' <summary>
''' Draws a bar in a DatGridView cell.
''' </summary>
''' <remarks></remarks>
Public Class Bar

    ''' <summary>
    ''' Draws a glass bar into a cell
    ''' </summary>
    ''' <param name="oColor">Color of the bar.</param>
    ''' <param name="e">CellPainting event's parameters</param>
    ''' <remarks></remarks>
    Public Shared Sub PintaDegradado(ByVal oColor As Drawing.Color, _
                  ByVal e As DataGridViewCellPaintingEventArgs)
        Bar.PintaDegradado(oColor, e, -1)
    End Sub

    ''' <summary>
    ''' Draws a partial glass bar into a cell
    ''' </summary>
    ''' <param name="oColor">Color of the bar.</param>
    ''' <param name="e">CellPainting event's parameters</param>
    ''' <param name="iPorcentaje">Percent value to represent.</param>
    ''' <remarks></remarks>
    Public Shared Sub PintaDegradado(ByVal oColor As Drawing.Color, _
           ByVal e As DataGridViewCellPaintingEventArgs, ByVal iPorcentaje As Integer)
        Dim aCol As Drawing.Color() = {oColor}
        Dim aPor As Integer() = {iPorcentaje}
        If iPorcentaje = -1 Then
            Dim aPorN As Integer() = {}
            Bar.PintaDegradado(aCol, e, aPorN)
        Else
            Bar.PintaDegradado(aCol, e, aPor)
        End If
    End Sub

    ''' <summary>
    ''' Draws a partial glass bar into a cell with target indicator.
    ''' </summary>
    ''' <param name="oColor">Color of the bar.</param>
    ''' <param name="e">CellPainting event's parameters</param>
    ''' <param name="iPorcentaje">Percent value to represent.</param>
    ''' <param name="iObjetivo">Target to show.</param>
    ''' <param name="oColorObjetivo">Target indicator color.</param>
    ''' <remarks></remarks>
    Public Shared Sub PintaDegradado(ByVal oColor As Drawing.Color, _
           ByVal e As DataGridViewCellPaintingEventArgs, ByVal iPorcentaje As Integer, _
           ByVal iObjetivo As Integer, ByVal oColorObjetivo As Drawing.Color)
        Dim aCol As Drawing.Color() = {oColor, oColorObjetivo}
        Dim aPor As Integer() = {iPorcentaje, iObjetivo}
        Bar.PintaDegradado(aCol, e, aPor)
    End Sub

    ''' <summary>
    ''' Does the hard job
    ''' </summary>
    ''' <param name="aColores">Color array to use.</param>
    ''' <param name="e">CellPainting event's parameters</param>
    ''' <param name="aPorcentajes">Percent array to show. It can be one or two. 
    ''' First shows bar percent and second shows target percent. 
    ''' If only one percent is passed and it's cero, 
    ''' it will fill all cell width with the glass bar.</param>
    ''' <remarks></remarks>
    Private Shared Sub PintaDegradado(ByVal aColores As Drawing.Color(), _
	ByVal e As DataGridViewCellPaintingEventArgs, ByVal aPorcentajes As Integer())

        '   Declares brushes and color array
        Dim oPin1 As Drawing2D.LinearGradientBrush = Nothing
        Dim oPin2 As Drawing2D.LinearGradientBrush = Nothing
        Dim oPinO As Drawing2D.LinearGradientBrush = Nothing
        Dim oColor As Drawing.Color = aColores(0)

        '   Handles any exception
        Try
            '   Gets cell rectangle
            Dim oCelda As New Rectangle(e.CellBounds.X - 1, e.CellBounds.Y - 1, _
		e.CellBounds.Width, e.CellBounds.Height)

            '   Debugs percent array
            For iC As Integer = 0 To aPorcentajes.Length - 1
                If aPorcentajes(iC) > 100 Then aPorcentajes(iC) = 100
            Next

            '   Declares rectangles.
            Dim oRect1 As Rectangle             ' Glass upper rect.
            Dim oRect2 As Rectangle             ' Glass lower rect.
            Dim oObj As Rectangle               ' Target rect.
            Dim oFond As Rectangle              ' Background rect.
            Dim oCuad As Rectangle = Nothing    ' Border rect.

            '   Declares percent variable
            Dim iPorcentaje As Integer = 0
            Dim bPor As Boolean = False

            '   Detects if percent(s) is/are passed
            '   One percent indicates only value percent.
            '   Two percents indicate value and target percent.
            If aPorcentajes.Length > 0 Then
                bPor = True
                iPorcentaje = aPorcentajes(0)

                If iPorcentaje > 0 Then

                    '   Gets rectangles and brushes for percent indicator.
                    oRect1 = New Rectangle(oCelda.X + 4, oCelda.Y + 4, _
			Math.Round(((oCelda.Width - 7) * iPorcentaje * 0.01) + 0.49),_
			 Math.Round((oCelda.Height - 8) / 2))
                    If oRect1.Width > oCelda.Width - 7 _
			Then oRect1.Width = oCelda.Width - 7
                    oRect2 = New Rectangle(oCelda.X + 4, oRect1.Bottom - 1, _
			oRect1.Width, (oCelda.Height - 6) - oRect1.Height)
                    oFond = New Rectangle(oCelda.X + 4, oCelda.Y + 4, _
			oCelda.Width - 7, oCelda.Height - 7)
                    oPin1 = New Drawing2D.LinearGradientBrush(oRect1, _
			Color.White, Color.FromArgb(180, oColor), _
			Drawing2D.LinearGradientMode.Vertical)
                    oPin2 = New Drawing2D.LinearGradientBrush(oRect2, _
			oColor, Color.FromArgb(70, oColor), _
			Drawing2D.LinearGradientMode.Vertical)
                End If

                If aPorcentajes.Length > 1 Then

                    '   Get rectangles and brushes for target indicator
                    Dim iObj As Integer = aPorcentajes(1)
                    Dim iPos As Integer = oCelda.X + 4 + Math.Round_
			(((oCelda.Width - 7) * iObj * 0.01) + 0.49)
                    Dim iIni As Integer = iPos - 20
                    If iIni < oCelda.X + 4 Then iIni = oCelda.X + 4
                    oObj = New Rectangle(iIni, oCelda.Y + 2, iPos - iIni, _
			oCelda.Height - 4)
                    oPinO = New Drawing2D.LinearGradientBrush(oObj, _
			Drawing.Color.FromArgb(0, aColores(1)), aColores(1), _
			Drawing2D.LinearGradientMode.Horizontal)
                End If

                '   Get border rectangle
                oCuad = New Rectangle(oCelda.X + 3, oCelda.Y + 3, oCelda.Width - 6, _
			oCelda.Height - 6)
            Else

                '   Gets rectangles and brushes to fill cell (no percents)
                oRect1 = New Rectangle(oCelda.X + 1, oCelda.Y + 1, _
			oCelda.Width - 1, Math.Round(oCelda.Height / 2))
                oRect2 = New Rectangle(oCelda.X + 1, oRect1.Bottom - 1, _
			oCelda.Width - 1, oCelda.Height - oRect1.Height)
                oFond = New Rectangle(oCelda.X + 1, oCelda.Y + 1, _
			oCelda.Width - 1, oCelda.Height)
                oPin1 = New Drawing2D.LinearGradientBrush(oRect1, _
			Color.White, Color.FromArgb(180, oColor), _
			Drawing2D.LinearGradientMode.Vertical)
                oPin2 = New Drawing2D.LinearGradientBrush(oRect2, _
			oColor, Color.FromArgb(70, oColor), _
			Drawing2D.LinearGradientMode.Vertical)

            End If

            '   Paints cell background
            e.PaintBackground(e.CellBounds, True)
            If bPor Then
                e.Graphics.DrawRectangle(Pens.DimGray, oCuad)
            End If

            '   Paints glass bar
            If oPin1 IsNot Nothing Then
                e.Graphics.FillRectangle(Brushes.White, oFond)
                e.Graphics.FillRectangle(oPin1, oRect1)
                e.Graphics.FillRectangle(oPin2, oRect2)
            End If

            '   Paints target indicator
            If oPinO IsNot Nothing Then
                e.Graphics.FillRectangle(oPinO, oObj)
            End If

            '   Paints cell contents
            e.PaintContent(oCelda)
            e.Paint(oCelda, DataGridViewPaintParts.Border)
            e.Handled = True
        Catch ex As Exception
            Debug.Print(ex.Message)
        Finally

            '   Dispose all resources
            If oPin1 IsNot Nothing Then
                oPin1.Dispose()
                oPin1 = Nothing
            End If
            If oPin2 IsNot Nothing Then
                oPin2.Dispose()
                oPin2 = Nothing
            End If
            If oPinO IsNot Nothing Then
                oPinO.Dispose()
                oPinO = Nothing
            End If
        End Try
    End Sub

End Class

Points of Interest

This code shows how to draw a glass effect bar: two gradient rectangles do the job. It also shows how to handle the DataGridView's cell painting manipulation. The bars are dynamically painted, so real time data updates are shown at real time. This allows to show real time progress bars too.

History

  • 4th June, 2010: Original version
  • 24th August, 2010: Article updated

License

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