En este artículo explicaré cómo conseguir colocar esas barras de progreso con efecto "glass" y del color que queramos en una columna de un DataGridView.
El código que comparto, también permite señalizar, por ejemplo un objetivo para poder comparar el valor real con dicho objetivo. Véase este ejemplo: en él se marca con el difusor verde el objetivo a alcanzar. Las líneas que lo superan aparecen en verde y las que no llegan en rojo.
Todo esto se consigue mediante un único método que, siendo informado adecuadamente de lo que queremos hacer, realiza todo el trabajo por nosotros.
Dicho método debe ser llamado desde el evento CellPainting del DataGridView. He aquí el código del método con todas sus formas de ser llamado (polimorfismo):
Public Class Barras
''' <summary>
''' Pinta el fondo de una celda con color degradado.
''' </summary>
''' <param name="oColor">Color a aplicar.</param>
''' <param name="e">Parámetros del evento CellPainting</param>
''' <remarks></remarks>
Public Shared Sub PintaDegradado(ByVal oColor As Drawing.Color, ByVal e As DataGridViewCellPaintingEventArgs)
Main.PintaDegradado(oColor, e, -1)
End Sub
''' <summary>
''' Pinta una barra de progreso en una celda de un control DataGridView
''' </summary>
''' <param name="oColor">Color a usar para la barra.</param>
''' <param name="e">Parámetros del evento CellPainting.</param>
''' <param name="iPorcentaje">Porcentaje a representar.</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() = {}
Main.PintaDegradado(aCol, e, aPorN)
Else
Main.PintaDegradado(aCol, e, aPor)
End If
End Sub
''' <summary>
''' Pinta una barra de progreso con señalización de objetivo en una celda de un control DataGridView.
''' </summary>
''' <param name="oColor">Color a usar para la barra.</param>
''' <param name="e">Parámetros del evento CellPainting.</param>
''' <param name="iPorcentaje">Porcentaje a representar.</param>
''' <param name="iObjetivo">Objetivo a marcar.</param>
''' <param name="oColorObjetivo">Color a usar para el objetivo.</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}
Main.PintaDegradado(aCol, e, aPor)
End Sub
''' <summary>
''' Pinta una barra en color degradado como fondo de una celda en un Grid.
''' </summary>
''' <param name="aColores">Matriz de colores a usar.</param>
''' <param name="e">Parámetros del evento CellPainting</param>
''' <param name="aPorcentajes">Matriz con los porcentajes a mostrar. Pueden ser uno o dos. El primero indica
''' el porcentaje de la barra de progreso a mostrar. El segundo un objetivo a marcar. Si sólo se indica uno y es cero,
''' se cubrirá todo el fondo de la celda con el primer color especificado.</param>
''' <remarks></remarks>
Private Shared Sub PintaDegradado(ByVal aColores As Drawing.Color(), ByVal e As DataGridViewCellPaintingEventArgs, ByVal aPorcentajes As Integer())
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)
Try
Dim oCelda As New Rectangle(e.CellBounds.X - 1, e.CellBounds.Y - 1, e.CellBounds.Width, e.CellBounds.Height)
For iC As Integer = 0 To aPorcentajes.Length - 1
If aPorcentajes(iC) > 100 Then aPorcentajes(iC) = 100
Next
Dim oRect1 As Rectangle
Dim oRect2 As Rectangle
Dim oObj As Rectangle
Dim oFond As Rectangle
Dim oCuad As Rectangle = Nothing
Dim iPorcentaje As Integer = 0
Dim bPor As Boolean = False
If aPorcentajes.Length > 0 Then
bPor = True
iPorcentaje = aPorcentajes(0)
If iPorcentaje > 0 Then
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
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
oCuad = New Rectangle(oCelda.X + 3, oCelda.Y + 3, oCelda.Width - 6, oCelda.Height - 6)
Else
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
If bPor Then
e.Graphics.DrawRectangle(Pens.DimGray, oCuad)
End If
If oPin1 IsNot Nothing Then
e.Graphics.FillRectangle(Brushes.White, oFond)
e.Graphics.FillRectangle(oPin1, oRect1)
e.Graphics.FillRectangle(oPin2, oRect2)
End If
If oPinO IsNot Nothing Then
e.Graphics.FillRectangle(oPinO, oObj)
End If
e.PaintContent(oCelda)
e.Paint(oCelda, DataGridViewPaintParts.Border)
e.Handled = True
Catch ex As Exception
Debug.Print(ex.Message)
Finally
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
Este método está listo para ser llamado desde el evento CellPainting del DataGridView. He aquí un ejemplo:Private Sub ctlLista_CellPainting(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellPaintingEventArgs) Handles ctlLista.CellPainting
Try
If e.ColumnIndex < 0 OrElse e.RowIndex < 0 Then Exit Sub
e.Handled = True
Dim oRow As Objetos.CapturaPesos.Registro = Nothing
Select Case DirectCast(e.ColumnIndex, Columnas)
Case Columnas.Peso
oRow = DirectCast(ctlLista.Rows(e.RowIndex).DataBoundItem, Equin.ApplicationFramework.ObjectView(Of Objetos.CapturaPesos.Registro)).Object
If oRow.Peso >= oRow.PesoMinimo AndAlso oRow.Peso <= oRow.PesoMaximo Then
Barras.PintaDegradado(Color.LightGreen, e)
Else
Barras.PintaDegradado(Color.Red, e)
End If
Case Else
e.Paint(e.CellBounds, DataGridViewPaintParts.All)
End Select
Catch ex As Exception
Debug.Print(ex.Message)
End Try
End Sub
Y eso es todo. Espero que disfrutéis con el truco.

