Sep 012020
 

Se trata de una suite de user controls, para crear gráficos estadísticos. Son cuatro controles pero algunos poseen estilos diferentes, se podría decir que están los principales y más utilizados. Cada user control es independiente del otro, por lo que no requiere implementar toda la suite, por supuesto esto no lo hace más óptimo en reducción de código, pero es esa costumbre de no depender de nada, son muchas lineas de código y seguramente habrá más de algún bugs dando vuelta, por mi parte creo que hasta aquí llegaron mis ganas con esto, por supuesto que si alguien encuentra algún error o sugerencia se agradece informar para corregirlo.

En la descarga se encuentra un ejemplo de cada uno y un proyecto principal que abarca todos y algunos agregados para simular un Dashboard.

DashBoard.png
PieChart.png
DonutChart.png
BarChart1.png
BarChart2.png
AreaChart.png
TreeMaps.png
TreeMaps2.png

Actualizado 21/12/2021, se añadió la función image() la cual retorna una imagen del grafico para poder imprimirla, esta tiene como parámetros opcionales Ancho y Alto para poder ajustar a la hoja de impresión, junto a los ejemplos individuales hay una demostración de como imprimir.

  52 Responses to “Charts control con GDI+”

  1. Muy Bueno, lo que recomendaría es ampliar el numero a tipo exploting, y también en los chart Barra, que se muestre los valores en la punta de la barra, sin la necesidad de pasar el mouse por encima de la imagen…

    • Hola gracias por las recomendaciones, no entiendo a que te referis con «tipo exploting», en cuanto a los valores se puede mostrar en en la punta de la barra, cambiar LabelsVisible =True y LabelsPositions = LP_ABOBE

  2. Al cambiar el valor de labelsvisible a true en barchar horizontal y ejecutar, arroja el error «El subindice esta fuera del intervalo» dirigiendo a General, DrawHorizontal, del control UcChartBar, Otro seria los modelos de Chart se aumentaria y tambien a 3D el Otro es que mostrara los labelsvisible en vertical en la punta del barra en forma de Pop Ups.

    Muchas Gracias por sus aportes

  3. 3D no está en mi lista de deseos, sería un lindo desafío pero, creo que hoy en día se ven muy pocos en 3D, está mas de moda lo simplista, lo plano, si buscas charts en google fijate que ya casi no muestran modelos 3D.

    Gracias por los errores mencionados.

  4. Gracias por el aporte., tengo hartos informes que llevar a gráficos y esta es una excelente opción.

    Saludos !!

  5. Por favor podrías hacer una demo con conexión ADO????

  6. Por favor podrias hacer conexion conADO. Gracias

  7. Boa tarde
    como facho pra imprimir este gráfico

  8. Si por favor Leandro deseamos que se conecte con Ado

  9. Después de utilizarlo un rato , no se porque los números decimales dan problemas, cuando uso .add int(valor) funciona correctamente.

    • Efectivamente no se porqué pero en ningún control que he probado se admiten números decimales. Además el control ChartArea no tiene método .clear así que no se como limpiar el grafico para recargar nuevos datos.
      Si pudiera darnos unas indicaciones se lo agradecería. Me parecen fantásticos estos desarrollos y definitivamente les dan otro aspecto a los viejos desarrollos de vb6.
      Gracias.

      • Hola Carlos, si tienes razón no tiene un método Clear, debería tenerlo, en cuanto a los decimales no note que este fallando, pero volveré a revisarlo, cualquier cosa deja un ejemplo aquí de que parámetros pasas, para encontrar mas fácil el error.

        • Buenos días:
          Gracias por el comentario. El error que nos aparece es «El objeto ya no es válido» Cuando pasamos por Function GetMax()
          Resulta que el valor de m_Serie(0).Values(1) i=0 y j=1 no está definido y falla la compraración If M < m_Serie(i).Values(j) Then
          Nos pasa siempre pero cuando forzamos valores enteros add int(valor) el error no ocurre. También decirle que esos valores vienen de un recorset y rellenemoslos mismos en un bucle algo que creemos no estará relacionado.

          If Not rs.EOF Then
          Set Value = New Collection
          With Value
          For i = 0 To 11
          .Add Int(rs(i)) ' Aquí es donde pasamos el valor al metodo add
          Next i
          End With
          chart_compras.AddLineSeries "Pagado", Value, &H800080
          End If

          Gracias por todo

        • Buenas de nuevo. Una vez que implementamos los números con decimales con punto en el ChartArea vemos que el eje Y no se forma bien porque no tiene en cuenta el punto.

          en la Función Getmax () del user control aun poniendo M como double M siempre coge un valor entero Si m_Serie(i).Values(j) =23456.45 por ejemplo M vale 2345645 con lo que getmax() devuelve un limite superior del eje erróneo.

          Private Function GetMax() As Single

          Dim i As Long, j As Long, M As Single

          For i = 0 To SerieCount – 1
          For j = 1 To m_Serie(i).Values.Count
          If M < m_Serie(i).Values(j) Then
          M = m_Serie(i).Values(j)
          End If
          Next
          Next

          GetMax = M

          End Function

          • Carlos ya probaste pasarlo directamente así

            .Add rs(i)

            porque por lo que entiendo el valor que se le esta pasando no es un decimal.

          • buenas Leandro:

            cuando paso rs(i) si

            .add 200 ‘ funciona ok
            .add 200,2 ‘ da error por ser una coma
            .add 200.2 ‘ funciona ok al pasarle decimales con punto pero la función getmax() no calcula bien el limite superior del eje Y porque en
            M = m_Serie(i).Values(j), M siempre elimina los puntos decimales.

            No se si me he explicado bien.

          • finalmente se pudo solucionar únicamente con

            .add format(rs(i),»0.00″) ‘ así todo funciona correctamente en el chart Area.

            Ahora encontré que el .value del Piechart no puede ser decimal, aparte del método .clear del chartArea
            Todo lo demás funciona de maravilla, gracias.

  10. Carlos, ahi subí nuevamente el .zip con con el clear del ChartArea, después de llamar a Clear, invocar a Refresh si se quiere mostrar el grafico limpio, de lo contrario volver a cargar los nuevos valores y después invocar a refresh.

    el value del Piechart si puede ser con decimales, de echo en ejemplo que se encuentra solo paso Rnd como valor aleatorio y este es casi siempre es un numero decimal.

    cualquier cosa me comentas.

  11. Buenas tardes; todo perfecto con el chartArea, disculpas pero me refería al objeto Progrescircular que es el que no admite decimales en un metodo .value.

    • Carlos, yo opte por mostrar un numero entero, ya que no me pareció necesario mostrar un decimal cuando hablamos de porcentaje, pero si vos queres mostrar el decimal podes cambiar esta linea dentro del usercontrol en la funcion «Draw»

      sDiplay = CStr(Portion * 100 \ Range) & «%»

      por esto

      sDiplay = CStr(Portion * 100 / Range) & «%»

  12. hola Leandro excelente control, se puede guardar como imagen o imprimir?

    • Hola Grabriel entre hoy o mañana estaré subiendo una actualizacion para que esto sea posible, agregare una propiedad «Image» para que esta se pueda utilizar con Printer.PaintPicture

      Saludos.

      • muy bueno, pero al compilar para ocx y usar en el proyecto el error de HasDc o Windowsless = true, y no se como solucionarlo
        Gracias.

        • Hola Jean, descárgalo y prueba nuevamente, he corregido algunas cosas que no funcionaban si estaban como ocx.

          Saludos.

  13. Leandro, meus parabéns, buscava este tipo de qualidade para os nosso projeto algum tempo.

  14. Leandro, realmente muy buenos controles, pero tengo un problema al llevar el control a mis proyectos me anda saliendo un error en el control de ucProgressCircular, al hacer clic en propiedades me sale error del proyecto del control y me manda el siguiente error….»Cadena de clase no válida» y los controles insertados desaparecen y en esa area aparece una franja negra, la única forma de volver a mostrar el formulario es cerrar y volver a abrir.

    Por favor una ayuda para poder salvar este problema, de antemano muchas gracias

    • Mil disculpas el error completo es «Cadena de clase no válido. Buscando un objeto con ProyID»

      Saludos nuevamente

  15. Un pequeño arreglo para ucCharArea.ctl ya que aunque tiene el código para ocultar los ejes y título no tiene las propiedades publicadas y no se puede usar. Añadiendo esto funciona correctamente:

    Public Property Get LegendVisible() As Boolean
    LegendVisible = m_LegendVisible
    End Property

    Public Property Let LegendVisible(ByVal New_Value As Boolean)
    m_LegendVisible = New_Value
    PropertyChanged «LegendVisible»
    Refresh
    End Property

    • Se ha cortado, esto es lo que hay que añadir:

      Public Property Get LegendVisible() As Boolean
      LegendVisible = m_LegendVisible
      End Property

      Public Property Let LegendVisible(ByVal New_Value As Boolean)
      m_LegendVisible = New_Value
      PropertyChanged «LegendVisible»
      Refresh
      End Property

      Public Property Get AxisXVisible() As Boolean
      AxisXVisible = m_AxisXVisible
      End Property

      Public Property Let AxisXVisible(ByVal New_Value As Boolean)
      m_AxisXVisible = New_Value
      PropertyChanged «AxisXVisible»
      Refresh
      End Property

      Public Property Get AxisYVisible() As Boolean
      AxisYVisible = m_AxisYVisible
      End Property

      Public Property Let AxisYVisible(ByVal New_Value As Boolean)
      m_AxisYVisible = New_Value
      PropertyChanged «AxisYVisible»
      Refresh
      End Property

  16. Hola Leandro!

    Estupendos controles para modernizar una aplicación legada que me llegó.

    Estoy tratando de integrarle tus gráficos a ella, pero tengo un problema específicamente con la gráfica de pie ucPieChart, que logré reproducir en el programa demo de estos controles.

    Se trata de simular un timer o un cambio de criterios dinámico que haga refrescar los datos periódicamente, utilizando para ello los métodos Clear y Refresh. Eventualmente arroja el error 28 Out of Stack Space en la rutina Draw
    en la línea:
    GdipCreatePath 0, m_Item(i).hPath

    Para reproducir la situación modifique la forma del demo, separando la carga de datos en la rutina Populate e incorporando un doble click en la forma para llamarla varias veces.

    El error se produce al hacer click varias veces en la forma.

    El código queda:


    Option Explicit
    Dim cResizer As ClsResizer

    Private Sub Form_DblClick()
    Populate
    End Sub

    Private Sub Form_Load()

    Set cResizer = New ClsResizer
    With cResizer
    .AddControlFont "ucProgressCircular", "Caption1_Font", "Caption2_Font"

    .AddControlFont "ucChartArea", "Font", "TitleFont"
    .AddControlFont "ucChartBar", "Font", "TitleFont"
    .AddControlFont "ucPieChart", "Font", "TitleFont"
    .AddControlFont "ucTreeMaps", "Font", "TitleFont"
    .AddControlFont "LabelPlus", "Font"

    .AddControlProperty "ucProgressCircular", "PB_Width", "PF_Width", "Caption1_OffsetY", "Caption2_OffsetY"
    .AddControlProperty "LabelPlus", "HotLineWidth"
    .AddControlProperty "ucChartArea", "LinesWidth"
    .AddControlProperty "ucPieChart", "SeparatorLineWidth", "DonutWidth"

    .SaveControlsPositions Me
    End With

    Populate

    End Sub

    Private Sub Populate()
    Dim cPalette As Collection
    Dim i As Long, j As Long
    Dim Value As Collection
    Dim Lables As Collection
    Dim Icons As Collection
    Dim keys As Collection
    Dim CustomColors As Collection
    Dim colDate As Collection

    Set cPalette = NewCollection(&H4744E3, &H50C187, &HABA56C, &H48BDBF, &H4D91F4, &H7450, &H3DB0EF)

    Randomize Timer
    ucPieChart1.Clear
    For i = 0 To 2
    ucPieChart1.AddItem "2000" + i, Random(10, 30), CLng(cPalette(i + 1))
    Next
    ucPieChart1.Refresh

    Set Value = New Collection
    For i = 0 To 6
    Value.Add Random(10, 10 * i)
    Next

    ucTreeMaps1.Clear
    Set Lables = New Collection
    With Lables
    .Add "Facebook"
    .Add "Intagram"
    .Add "Wikipedia"
    .Add "Pinterest"
    .Add "WhatsApp"
    .Add "Twiter"
    .Add "Youtube"
    End With
    ucTreeMaps1.AddLineSeries vbNullString, vbBlue, Value, Lables
    ucTreeMaps1.Refresh

    ucChartBar1.Clear
    Set Value = New Collection
    Set colDate = New Collection
    For i = 1 To 12
    Value.Add Random(10, 300)
    colDate.Add Format(DateSerial(2020, i, 1), "mmm")
    Next
    ucChartBar1.AddAxisItems colDate, , 305, 2
    ucChartBar1.AddSerie "ASDF", vbRed, Value
    ucChartBar1.Refresh

    Set Value = New Collection
    For i = 1 To cPalette.Count
    Value.Add Random(0, 100 * i)
    Next

    ucChartBar2.Clear
    ucChartBar2.AddAxisItems Lables, True, , 2
    ucChartBar2.AddSerie "Serie 1", vbRed, Value, cPalette
    ucChartBar2.Refresh

    ucChartArea1.Clear
    For j = 1 To 3
    Set Value = New Collection
    For i = 1 To cPalette.Count
    Value.Add Random(10 * i, 100 * i)
    Next
    ucChartArea1.AddLineSeries "Serie " & j, Value, cPalette(j)
    Next
    ucChartArea1.Refresh

    ucChartArea2.Clear
    For j = 1 To 2
    Set Value = New Collection
    For i = 1 To cPalette.Count
    Value.Add Random(10 * i, 100 * i)
    Next
    ucChartArea2.AddLineSeries "Serie " & j, Value, cPalette(j + 5)
    Next
    ucChartArea2.Refresh

    ucPieChart2.Clear
    For i = 1 To 5
    ucPieChart2.AddItem "Serie " & i, Random(10, 100), cPalette(i)
    Next
    ucPieChart2.Refresh

    End Sub

    etc...

    ¿me puedes decir qué estoy haciendo mal o como debo hacerlo adecuadamente?

    Gracias!

    • Hola Gracias por informar, hay un pequeño error en el clear del pie chart, con esto se soluciona

      Public Sub Clear()
      Dim i As Long
      For i = 0 To ItemsCount – 1
      GdipDeletePath m_Item(i).hPath
      m_Item(i).hPath = 0
      Next
      ItemsCount = 0
      ReDim Preserve m_Item(0)
      Me.Refresh
      End Sub

      de todas formas actualice la descarga, además agregue un control de error en el draw del ucChartArea

  17. Leandro, tus creaciones para VB6 son fantásticas.

    Respecto a este Chart Control GDI+, persiste un error en UserControl.Mousemove.
    Mientras no se carga el gráfico, si el usuario tiene el mouse sobre el UserControl, da un error (err 9) en esta rutina. Ya intenté controlar el acceso al mismo saltándome la rutina con una variable booleana, pero una vez activada el error persiste.

    ¿Cómo podría solucionar este problema?

    Control de usuario: ucChartBar
    Rutina: UserControl_MouseMove
    Línea: If PtInRectL(.Rects(j – 1), X, Y) Entonces
    Error: 9

    • Logré solucionar el problema con una variable booleana que desactiva la rutina Mousemove y se activa cuando el usuario hace clic en el gráfico. De esta forma se evita el problema, pero sigo creyendo que se puede hacer alguna corrección en la rutina de la herramienta.

    • Otra rutina que tiene un problema es Resizer.Resize Controls Me (dentro de form_resize)

    • Hay un problema persistente que no puedo solucionar, ni siquiera insertando un control de errores.

      ucChartBar
      UserControl_MouseMove
      Err 9:
      line: If PtInRectL(.Rects(j - 1), X, Y) Then

  18. Me gustó mucho esta herramienta, es como llevar el mundo moderno a Visual Basic 6. Aunque es limitado en algunos aspectos.

    Por ejemplo, necesito desarrollar un mejor gráfico de flujo de caja, con la posibilidad de cambiar el tamaño de las etiquetas, tener la posibilidad de un desplazamiento horizontal para ajustar más información, tener la posibilidad de interactuar con los elementos internos del gráfico, tomar a las posibilidades de un power BI dentro de vb6.

    Me gustaría saber si hay alguna intención de seguir desarrollando esta herramienta. Estaría dispuesto a comprarlo, sería muy justo.

    • Hola Ricardo, la verdad por momento no tengo intenciones de seguir trabajando nuevas implementaciones al control, si corregiré si es que hay un error que me indique entonces si hare la modificación.

      Saludos.

      • Su herramienta es fantástica y valdría la pena pagar por ella. Creo que la comunidad vb6 piensa lo mismo. Felicitaciones por el trabajo.

  19. Hola Leandro,

    Quiero utilzar la gráfica de barras de ucBarChart, y mostrar las etiquetas con valores desde inicio.

    El problema es que no encuentro la manera de manejar adecuadamente la propiedad LabelsVisible.

    Si la inicializo en True desde las propiedades del control, me da un error. Si lo intento hacer por código, obtengo el mismo resultado.

    El error es reproducible desde el programa demo del control ucBarChart.

    En el From2 que se activa desde el botón de Colors del Form1:

    a) Si pongo desde las propiedades del ucChartBar1(3) LabelsVisible=True, al correr el demo e invocar la Form2, da el error.

    b) Si dentro del código incluyo el evento Click, por ejemplo:


    Private Sub ucChartBar1_Click(Index As Integer)
    ucChartBar1(Index).LabelsVisible = Not (ucChartBar1(Index).LabelsVisible)
    End Sub

    Da el error sólo en la 4ª gráfica ( ucChartBar1(3) )

    El error es Error 9 Suscript Out of Range, línea 2416 de ucChartBar:
    lColor = m_Serie(i).CustomColors(j)

    ¿Puedes orientarme cómo debo hacerlo apropiadamente por favor? Gracias!

    • Hola Jorge, es un bugs, no lo había notado, pero por suerte es fácil de solucionar el problema es que CustomColors es una colección y le estoy pasando un index 0 asi que solo basta con sumarle 1 a j

      remplazace dentro del usercontrol todos los:

      m_Serie(i).CustomColors(j)

      por

      m_Serie(i).CustomColors(j + 1)

      esto esta en dos lados.

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(required)

(required)