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 ClassEste 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 SubY eso es todo. Espero que disfrutéis con el truco.
Buen efecto conseguido. ;)
ResponderEliminarTenéis disponible una versión que he publicado de este artículo con un proyecto de ejemplo en http://www.codeproject.com/KB/grid/barchartdatagridview.aspx.
ResponderEliminarEstá en inglés.
Me encantaria aplicar las barras de progreso a un datagrid que uso como pianoroll midi, el cual dispara notas segun valor de cada cell.
ResponderEliminarQuisiera saber si estarias interesado en adaptarlo a mi app, bien remunerado por supuesto. Gracias circex@telefonica.net