Results 1 to 18 of 18

Thread: VB.net Doughnut Piecharts

  1. #1

    Thread Starter
    Member
    Join Date
    Apr 2008
    Posts
    40

    VB.net Doughnut Piecharts

    Hi,

    Can someone tell me how to draw doughnut chart using vb.net gdi+ ?. The doughnut chart is similiar to pie chart (relative pie charts )

  2. #2
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    Re: VB.net Doughnut Piecharts

    A doughnut is simply a pie with the middle taken out, so that's exactly what you draw. You call DrawPie multiple times to draw a pie chart, then you call DrawPie the same number of times again with the same centre and angles but a smaller radius to "take out" the middle.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  3. #3

    Thread Starter
    Member
    Join Date
    Apr 2008
    Posts
    40

    Re: VB.net Doughnut Piecharts

    Thanks for your reply

    but when I try to draw and color multiple pie with the same center and different radii. The one which I had drawn recently is overdrawing the existing. I want to remove that overlapping. How would I do that.Please let me know if you aren't clear about my doubt.
    Last edited by saechira; Jul 3rd, 2008 at 02:22 AM.

  4. #4
    Addicted Member sauronsmatrix's Avatar
    Join Date
    Jun 2008
    Location
    USA
    Posts
    133

    Re: VB.net Doughnut Piecharts

    Heres the code for making a pie chart based on 4 numbers, which colors them randomly. lol i made this for school


    vb Code:
    1. Public Class Form1
    2.     Inherits System.Windows.Forms.Form
    3. #Region " Windows Form Designer generated code "
    4.  
    5.     Public Sub New()
    6.         MyBase.New()
    7.  
    8.         'This call is required by the Windows Form Designer.
    9.         InitializeComponent()
    10.  
    11.         'Add any initialization after the InitializeComponent() call
    12.  
    13.     End Sub
    14.  
    15.     'Form overrides dispose to clean up the component list.
    16.     Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
    17.         If disposing Then
    18.             If Not (components Is Nothing) Then
    19.                 components.Dispose()
    20.             End If
    21.         End If
    22.         MyBase.Dispose(disposing)
    23.     End Sub
    24.  
    25.     'Required by the Windows Form Designer
    26.     Private components As System.ComponentModel.IContainer
    27.  
    28.     'NOTE: The following procedure is required by the Windows Form Designer
    29.     'It can be modified using the Windows Form Designer.  
    30.     'Do not modify it using the code editor.
    31.     Friend WithEvents btnChart As System.Windows.Forms.Button
    32.     Friend WithEvents lblInfo As System.Windows.Forms.Label
    33.     Friend WithEvents tx1 As System.Windows.Forms.TextBox
    34.     Friend WithEvents tx2 As System.Windows.Forms.TextBox
    35.     Friend WithEvents tx3 As System.Windows.Forms.TextBox
    36.     Friend WithEvents tx4 As System.Windows.Forms.TextBox
    37.     Friend WithEvents lblPie As System.Windows.Forms.Label
    38.     Friend WithEvents lblPercent As System.Windows.Forms.Label
    39.     <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
    40.         Me.btnChart = New System.Windows.Forms.Button
    41.         Me.lblInfo = New System.Windows.Forms.Label
    42.         Me.tx1 = New System.Windows.Forms.TextBox
    43.         Me.tx2 = New System.Windows.Forms.TextBox
    44.         Me.tx3 = New System.Windows.Forms.TextBox
    45.         Me.tx4 = New System.Windows.Forms.TextBox
    46.         Me.lblPie = New System.Windows.Forms.Label
    47.         Me.lblPercent = New System.Windows.Forms.Label
    48.         Me.SuspendLayout()
    49.         '
    50.         'btnChart
    51.         '
    52.         Me.btnChart.BackColor = System.Drawing.Color.FromArgb(CType(255, Byte), CType(128, Byte), CType(128, Byte))
    53.         Me.btnChart.Location = New System.Drawing.Point(24, 104)
    54.         Me.btnChart.Name = "btnChart"
    55.         Me.btnChart.Size = New System.Drawing.Size(104, 24)
    56.         Me.btnChart.TabIndex = 0
    57.         Me.btnChart.Text = "Chart"
    58.         '
    59.         'lblInfo
    60.         '
    61.         Me.lblInfo.Location = New System.Drawing.Point(16, 24)
    62.         Me.lblInfo.Name = "lblInfo"
    63.         Me.lblInfo.Size = New System.Drawing.Size(96, 24)
    64.         Me.lblInfo.TabIndex = 1
    65.         Me.lblInfo.Text = "Enter four values:"
    66.         Me.lblInfo.TextAlign = System.Drawing.ContentAlignment.MiddleRight
    67.         '
    68.         'tx1
    69.         '
    70.         Me.tx1.Location = New System.Drawing.Point(128, 24)
    71.         Me.tx1.Name = "tx1"
    72.         Me.tx1.Size = New System.Drawing.Size(112, 20)
    73.         Me.tx1.TabIndex = 2
    74.         Me.tx1.Text = "10"
    75.         '
    76.         'tx2
    77.         '
    78.         Me.tx2.Location = New System.Drawing.Point(248, 24)
    79.         Me.tx2.Name = "tx2"
    80.         Me.tx2.Size = New System.Drawing.Size(112, 20)
    81.         Me.tx2.TabIndex = 3
    82.         Me.tx2.Text = "20"
    83.         '
    84.         'tx3
    85.         '
    86.         Me.tx3.Location = New System.Drawing.Point(368, 24)
    87.         Me.tx3.Name = "tx3"
    88.         Me.tx3.Size = New System.Drawing.Size(112, 20)
    89.         Me.tx3.TabIndex = 4
    90.         Me.tx3.Text = "30"
    91.         '
    92.         'tx4
    93.         '
    94.         Me.tx4.Location = New System.Drawing.Point(488, 24)
    95.         Me.tx4.Name = "tx4"
    96.         Me.tx4.Size = New System.Drawing.Size(112, 20)
    97.         Me.tx4.TabIndex = 5
    98.         Me.tx4.Text = "40"
    99.         '
    100.         'lblPie
    101.         '
    102.         Me.lblPie.Location = New System.Drawing.Point(248, 80)
    103.         Me.lblPie.Name = "lblPie"
    104.         Me.lblPie.Size = New System.Drawing.Size(301, 301)
    105.         Me.lblPie.TabIndex = 6
    106.         '
    107.         'lblPercent
    108.         '
    109.         Me.lblPercent.Location = New System.Drawing.Point(128, 56)
    110.         Me.lblPercent.Name = "lblPercent"
    111.         Me.lblPercent.Size = New System.Drawing.Size(472, 16)
    112.         Me.lblPercent.TabIndex = 7
    113.         '
    114.         'Form1
    115.         '
    116.         Me.AcceptButton = Me.btnChart
    117.         Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
    118.         Me.ClientSize = New System.Drawing.Size(616, 405)
    119.         Me.Controls.Add(Me.lblPercent)
    120.         Me.Controls.Add(Me.lblPie)
    121.         Me.Controls.Add(Me.tx4)
    122.         Me.Controls.Add(Me.tx3)
    123.         Me.Controls.Add(Me.tx2)
    124.         Me.Controls.Add(Me.tx1)
    125.         Me.Controls.Add(Me.lblInfo)
    126.         Me.Controls.Add(Me.btnChart)
    127.         Me.MaximizeBox = False
    128.         Me.MaximumSize = New System.Drawing.Size(624, 432)
    129.         Me.MinimumSize = New System.Drawing.Size(624, 432)
    130.         Me.Name = "Form1"
    131.         Me.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen
    132.         Me.Text = "Pie Chart"
    133.         Me.ResumeLayout(False)
    134.  
    135.     End Sub
    136.  
    137. #End Region
    138.     Private Sub btnChart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnChart.Click
    139.         If IsNumeric(tx1.Text) = False Or IsNumeric(tx2.Text) = False Or IsNumeric(tx3.Text) = False Or IsNumeric(tx4.Text) = False Then
    140.             MessageBox.Show("Please only choose numbers", "Idiot Alert!")
    141.             Exit Sub
    142.         End If
    143.         Dim Chart As Graphics = Me.lblPie.CreateGraphics
    144.         Chart.Clear(Color.FromKnownColor(KnownColor.Control))
    145.         Dim pBlack As New Pen(Color.Black, 2)
    146.         'store brushes in an array for ease in a loop
    147.  
    148.         Dim intSum As Integer = Int(tx1.Text) + Int(tx2.Text) + Int(tx3.Text) + Int(tx4.Text)
    149.         Dim intPercent() As Decimal = {(tx1.Text / intSum), (tx2.Text / intSum), (tx3.Text / intSum), (tx4.Text / intSum)}
    150.  
    151.         lblPercent.Text = ""
    152.         Chart.DrawEllipse(pBlack, 0, 0, 300, 300)
    153.         Dim intCount As Integer
    154.         Dim intNext As Decimal = 0
    155.         Randomize()
    156.         For intCount = 0 To 3
    157.             Dim randBrush As New SolidBrush(Color.FromArgb(CType(Rnd() * 255, Byte), CType(Rnd() * 255, Byte), CType(Rnd() * 255, Byte)))
    158.             Chart.FillPie(randBrush, 0, 0, 300, 300, intNext, (intPercent(intCount) * 360))
    159.             intNext = intNext + (intPercent(intCount) * 360)
    160.             lblPercent.Text = lblPercent.Text & Math.Round(intPercent(intCount) * 100, 2) & "% " & "                            "
    161.         Next
    162.     End Sub
    163. End Class

  5. #5

    Thread Starter
    Member
    Join Date
    Apr 2008
    Posts
    40

    Re: VB.net Doughnut Piecharts

    I want to draw a doughchart on picturebox control of the form.

  6. #6
    Addicted Member sauronsmatrix's Avatar
    Join Date
    Jun 2008
    Location
    USA
    Posts
    133

    Re: VB.net Doughnut Piecharts

    So just declare a new graphics class on the PictureBox and use that general code, but at the end, tell it to paint a circle that is the same color of your form's background to achieve the doughnut chart effect.

  7. #7

    Thread Starter
    Member
    Join Date
    Apr 2008
    Posts
    40

    Re: VB.net Doughnut Piecharts

    Yep. As I mentioned relative (multiple layer doughnuts). using the above method I could do it for single doughnut.How about a doughnut like the one in this link. It need not be exploded. Slicing with spaces is not required. I am really struck up here.

    http://dotnetcharts.com/gallery/gall...uctname=Charts
    Last edited by saechira; Jul 3rd, 2008 at 11:45 PM.

  8. #8
    Addicted Member sauronsmatrix's Avatar
    Join Date
    Jun 2008
    Location
    USA
    Posts
    133

    Re: VB.net Doughnut Piecharts

    Well you can use the code I gave you to get the general process of drawing elliptical objects based on a numeric value and its percentage in the total, and using that;

    1) Make it draw starting from the outermost doughnut.
    2) Each time a doughnut layer is drawn, make it draw a circle that is filled with the background color of the form.
    3) ??????
    4) PROFIT!

    Lol, but on a serious note, do you get what I'm saying and how to do everything?

  9. #9

    Thread Starter
    Member
    Join Date
    Apr 2008
    Posts
    40

    Re: VB.net Doughnut Piecharts

    yes what you have ssaid is true.

    But my requirement goes like this.


    In my application I cannot start always with the outermost doughnut (pie). I have 2 doughnut pies. I need to draw it dynamically. Sometimes I may need to color the inner pie. Later when I need to color the outer pie then its overdrawing the innerpie. To avoid that I have to repaint the innercircle (the one which has been overdrawn, with the same color and sweep angles). How would I do that.
    Determing the angles while drawing doughnut is possible, but repainting the existing circle (the clip) is difficult. can I capture the inner pie into clip before drawing the outer pie.

  10. #10
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    Re: VB.net Doughnut Piecharts

    Quote Originally Posted by saechira
    In my application I cannot start always with the outermost doughnut
    Yes, you can. When you use GDI+ you have to redraw everything on each Paint event anyway. All you have to do is make sure that each graph is within the one drawn before it. If you only want to draw the inner graph then you just draw that. If you then want to add the outer graph you simply add it to the list of graphs to draw before the existing graph. In your Paint event handler you'll loop through all the graphs to draw and you'll draw them outer to inner.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  11. #11

    Thread Starter
    Member
    Join Date
    Apr 2008
    Posts
    40

    Re: VB.net Doughnut Piecharts

    Got u ..To draw the outer pie : I should add the outer pie to the list of existing pies. But would the contents of the inner circle(sweep angles, colors..) be retained. How would I repaint the circles without lossing any content. As I am new to .Net, I dont know how to repaint(). I apologize for the ignorance.



    >If you then want to add the outer graph you simply add it to the list of
    >graphs to draw before the existing graph.

  12. #12
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    Re: VB.net Doughnut Piecharts

    Here are some classes you will find useful:
    Code:
    Public Class DoughnutChartPart
    
        Private _colour As Color
        Private _text As String
        Private _value As Single
    
        Public Property Colour() As Color
            Get
                Return Me._colour
            End Get
            Set(ByVal value As Color)
                Me._colour = value
            End Set
        End Property
    
        Public Property Text() As String
            Get
                Return Me._text
            End Get
            Set(ByVal value As String)
                Me._text = value
            End Set
        End Property
    
        Public Property Value() As Single
            Get
                Return Me._value
            End Get
            Set(ByVal value As Single)
                Me._value = value
            End Set
        End Property
    
        Public Sub New()
        End Sub
    
        Public Sub New(ByVal color As Color, _
                       ByVal text As String, _
                       ByVal value As Single)
            Me._colour = color
            Me._text = text
            Me._value = value
        End Sub
    
    End Class
    Code:
    Public Class DoughnutChartPartCollection
        Inherits System.Collections.ObjectModel.Collection(Of DoughnutChartPart)
    End Class
    Code:
    Public Class DoughnutChart
    
        Private Const FULL_CIRCLE As Single = 360.0F
        Private Const DEGREES_TO_RADIANS As Single = Math.PI / 180.0F
        Private Const RADIANS_TO_DEGREES As Single = 1 / DEGREES_TO_RADIANS
    
    
        Private _centre As Point
        Private _innerRadius As Single
        Private _outerRadius As Single
        Private _parts As New DoughnutChartPartCollection
        Private _startAngle As Single
        Private _sweepAngle As Single
    
    
        Public Property Centre() As Point
            Get
                Return Me._centre
            End Get
            Set(ByVal value As Point)
                Me._centre = value
            End Set
        End Property
    
        Public Property InnerRadius() As Single
            Get
                Return Me._innerRadius
            End Get
            Set(ByVal value As Single)
                If value < 0.0 Then
                    Throw New ArgumentException("The inner radius cannot be less than zero.")
                End If
    
                If value > Me.OuterRadius Then
                    Throw New ArgumentException("The inner radius cannot be greater than the outer radius.")
                End If
    
                Me._innerRadius = value
            End Set
        End Property
    
        Public Property OuterRadius() As Single
            Get
                Return Me._outerRadius
            End Get
            Set(ByVal value As Single)
                If value < 0.0 Then
                    Throw New ArgumentException("The outer radius cannot be less than zero.")
                End If
    
                If value < Me.InnerRadius Then
                    Throw New ArgumentException("The outer radius cannot be less than the inner radius.")
                End If
    
                Me._outerRadius = value
            End Set
        End Property
    
        Public ReadOnly Property Parts() As DoughnutChartPartCollection
            Get
                Return Me._parts
            End Get
        End Property
    
        Public Property StartAngle() As Single
            Get
                Return Me._startAngle
            End Get
            Set(ByVal value As Single)
                value = value Mod FULL_CIRCLE
    
                If value < 0.0 Then
                    value = FULL_CIRCLE + value
                End If
    
                'The angle is now guaranteed to be in the range 0.0 <= value < 360.0.
                Me._startAngle = value
            End Set
        End Property
    
        Public Property SweepAngle() As Single
            Get
                Return Me._sweepAngle
            End Get
            Set(ByVal value As Single)
                If value < 0.0 OrElse value > FULL_CIRCLE Then
                    Throw New ArgumentOutOfRangeException("The sweep cannot be less than zero and must be less than 360.")
                End If
    
                Me._sweepAngle = value
            End Set
        End Property
    
    
        Public Sub New(ByVal outerRadius As Single, _
                       ByVal innerRadius As Single)
            Me.New(outerRadius, _
                   innerRadius, _
                   Point.Empty)
        End Sub
    
        Public Sub New(ByVal outerRadius As Single, _
                       ByVal innerRadius As Single, _
                       ByVal centre As Point, _
                       ByVal ParamArray parts As DoughnutChartPart())
            Me.New(outerRadius, _
                   innerRadius, _
                   centre, _
                   0.0, _
                   FULL_CIRCLE, _
                   parts)
        End Sub
    
        Public Sub New(ByVal outerRadius As Single, _
                       ByVal innerRadius As Single, _
                       ByVal centre As Point, _
                       ByVal startAngle As Single, _
                       ByVal sweepAngle As Single, _
                       ByVal ParamArray parts As DoughnutChartPart())
            Me.OuterRadius = outerRadius
            Me.InnerRadius = innerRadius
            Me.Centre = centre
            Me.StartAngle = startAngle
            Me.SweepAngle = sweepAngle
    
            For Each part As DoughnutChartPart In parts
                Me.Parts.Add(part)
            Next
        End Sub
    
    
        Public Sub Draw(ByVal g As Graphics, ByVal backColor As Color)
            Dim totalValue As Single = 0.0F
            Dim part As DoughnutChartPart
    
            'Sum the values.
            For Each part In Me.Parts
                totalValue += part.Value
            Next
    
            Dim sweepAngle As Single = Me.SweepAngle
            Dim sweepAngles As New Dictionary(Of DoughnutChartPart, Single)
    
            'Determine the sweep angles of the parts.
            For Each part In Me.Parts
                sweepAngles.Add(part, sweepAngle * part.Value / totalValue)
            Next
    
            Dim startAngle As Single = Me.StartAngle
            Dim centre As Point = Me.Centre
            Dim outerRadius As Single = Me.OuterRadius
            Dim outerDiameter As Single = 2 * outerRadius
    
            For Each part In Me.Parts
                sweepAngle = sweepAngles(part)
    
                Using brush As New SolidBrush(part.Colour)
                    g.FillPie(brush, _
                              centre.X - outerRadius, _
                              centre.Y - outerRadius, _
                              outerDiameter, _
                              outerDiameter, _
                              startAngle, _
                              sweepAngle)
                End Using
    
                startAngle += sweepAngle
            Next
    
            Dim innerRadius As Single = Me.InnerRadius
            Dim innerDiameter As Single = 2 * innerRadius
    
            Using brush As New SolidBrush(backColor)
                g.FillEllipse(brush, _
                              centre.X - innerRadius, _
                              centre.Y - innerRadius, _
                              innerDiameter, _
                              innerDiameter)
            End Using
        End Sub
    
    End Class
    Create a new Windows Forms project and add those classes to it. Now add the following code to your form:
    Code:
    Private doughnut As DoughnutChart
    
    Private Sub Form1_Load(ByVal sender As Object, _
                           ByVal e As EventArgs) Handles MyBase.Load
        Me.doughnut = New DoughnutChart(200, _
                                        150, _
                                        New Point(200, 200), _
                                        New DoughnutChartPart(Color.Red, "Red", 10), _
                                        New DoughnutChartPart(Color.Green, "Green", 20), _
                                        New DoughnutChartPart(Color.Blue, "Blue", 30))
    End Sub
    
    Private Sub Form1_Paint(ByVal sender As Object, _
                            ByVal e As PaintEventArgs) Handles Me.Paint
        Me.doughnut.Draw(e.Graphics, Me.BackColor)
    End Sub
    Now run the project and BEHOLD!

    Now change the code in the form to this:
    Code:
    Private doughnuts As New List(Of DoughnutChart)
    
    Private Sub Form1_Load(ByVal sender As Object, _
                           ByVal e As EventArgs) Handles MyBase.Load
        Me.doughnuts.Add(New DoughnutChart(200, _
                                           150, _
                                           New Point(200, 200), _
                                           New DoughnutChartPart(Color.Red, "Red", 10), _
                                           New DoughnutChartPart(Color.Green, "Green", 20), _
                                           New DoughnutChartPart(Color.Blue, "Blue", 30)))
        Me.doughnuts.Add(New DoughnutChart(100, _
                                           50, _
                                           New Point(200, 200), _
                                           45, _
                                           270, _
                                           New DoughnutChartPart(Color.Cyan, "Cyan", 40), _
                                           New DoughnutChartPart(Color.Magenta, "Magenta", 50), _
                                           New DoughnutChartPart(Color.Yellow, "Yellow", 60)))
    End Sub
    
    Private Sub Form1_Paint(ByVal sender As Object, _
                            ByVal e As PaintEventArgs) Handles Me.Paint
        For Each doughnut As DoughnutChart In Me.doughnuts
            doughnut.Draw(e.Graphics, Me.BackColor)
        Next
    End Sub
    Now run the project and BEHOLD again. I'll leave it up to you to make any improvements that are required, including drawing the text on each part. Just remember that the items in the List are drawn from first index to last, so they must be in order from outer to inner.
    Last edited by jmcilhinney; Jul 4th, 2008 at 03:50 AM.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  13. #13

    Thread Starter
    Member
    Join Date
    Apr 2008
    Posts
    40

    Re: VB.net Doughnut Piecharts

    Isn't there any way to capture the existing inner circle into clip instead of redrawing the inner circle part by part. please Correct me if I am wrong. Does n't the vb.net automatically capture the existing the graphics and redraw similiar on repaint()

  14. #14
    Frenzied Member MaximilianMayrhofer's Avatar
    Join Date
    Aug 2007
    Location
    IM IN YR LOOP
    Posts
    2,001

    Re: VB.net Doughnut Piecharts

    you could invalidate a specific part of your form, i suppose..

  15. #15

    Thread Starter
    Member
    Join Date
    Apr 2008
    Posts
    40

    Re: VB.net Doughnut Piecharts

    In case of drawing the inner circle pie (filling the inner pie parts)

    where should I mention that first redraw the outer pie and then only draw the inner pie(fill in the pie).Is it in the Invalidated() event of picture box ? If so how do I ensure that while redrawing the pies their parts (sweep angles) are retained ? Are the parts (sweep angles)retained automatically. If it is automatically retained how would I add parts to the inner pie?

    The following is the sample code which I have written. Hope it is easy to understand

    Code:
    Imports System.Drawing
    
    
    Public Class Form1
        Dim r As Region
        Dim g As Graphics
        Dim mypen As Pen = Pens.Beige
    
    
        Private Sub PictureBox1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles PictureBox1.Click
          
    
        End Sub
    
        Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
            r = Me.PictureBox1.Region()
            MessageBox.Show("In F paint")
            mypen = New Pen(Color.CornflowerBlue)
            
            g.DrawEllipse(Pens.OrangeRed, 50, 50, 50, 50)
            g.DrawEllipse(Pens.OrangeRed, 25, 25, 100, 100)
    
            mypen = Pens.Red
            g.FillPie(Brushes.Blue, 25, 25, 100, 100, 0, 45)
            g.FillPie(Brushes.Red, 50, 50, 50, 50, 0, 45)
    
        End Sub
    
        Private Sub PictureBox1_Invalidated(ByVal sender As Object, ByVal e As System.Windows.Forms.InvalidateEventArgs) Handles PictureBox1.Invalidated
    
        End Sub
    
        Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
            MessageBox.Show("In PB  paint")
            mypen = Pens.Aqua
            Me.Invalidate()
        End Sub
    
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            g = PictureBox1.CreateGraphics
    
        End Sub
    End Class

  16. #16
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    Re: VB.net Doughnut Piecharts

    You seem not to be getting this bit: EVERYTHING gets redrawn EVERY time. EVERY time the Paint event is raised you must execute code to draw EVERYTHING. That's the way it ALWAYS works. So, your Paint event handler draws EVERYTHING, then the system decides which parts of that actually get repainted to the screen based on your calls Invalidate. If you invalidate only a small rectangle in the top left corner of the form then the system will take the contents of that rectangle from your drawing and paint it to the screen.

    Now, the whole point of my creating those classes is so that they contain, and therefore retain, all the data about the objects they represent. You set the sweep angle of a chart once and it stays that value all the time, until you set the SweepAngle property to a different value.

    All the parts of a chart are stored in its Parts collection property. If you want to add a part to a chart you simply create a new DoughnutChartPart object and then call the Add method of the chart's Parts collection, e.g.
    vb.net Code:
    1. myChart.Parts.Add(New DoughnutChartPart(Color.Pink, "Pink", 45))
    You would then call Invalidate and Update to force the area containing that chart to redraw and it would automatically update itself to accommodate the new part.

    Let's go back to my second example, with the two charts. Try adding two Buttons to your form and then add this code:
    Code:
    Private Sub Button1_Click(ByVal sender As Object, _
                              ByVal e As EventArgs) Handles Button1.Click
        'Add a part to the outer chart.
        Me.AddPart(Me.doughnuts(0), Color.Orange, 40)
    End Sub
    
    Private Sub Button2_Click(ByVal sender As Object, _
                              ByVal e As EventArgs) Handles Button2.Click
        'Add a part to the inner chart.
        Me.AddPart(Me.doughnuts(1), Color.Purple, 70)
    End Sub
    
    Private Sub AddPart(ByVal chart As DoughnutChart, _
                        ByVal color As Color, _
                        ByVal value As Integer)
        'Add a new part.
        chart.Parts.Add(New DoughnutChartPart(color, _
                                              color.ToString(), _
                                              value))
    
        Dim centre As Point = chart.Centre
        Dim radius As Integer = CInt(Math.Ceiling(chart.OuterRadius))
        Dim diameter As Integer = 2 * radius
    
        'Redraw the chart to display the new part.
        Me.Invalidate(New Rectangle(centre.X - radius, _
                                    centre.Y - radius, _
                                    diameter, _
                                    diameter))
        Me.Update()
    End Sub
    Now run the project again and see that the charts look the same as before. Now click the Button1 and see that the new part gets added to the outer chart. The same start angle and sweep angle are used because they are stored in the chart itself and have not been changed. The area that gets repainted is the smallest rectangle that contains the outer chart.

    Now click Button2 and see that a new part gets added to the inner chart. Again, the same start and sweep angle are used because they are part of the chart. This time the area that gets repainted in the smallest rectangle that contains the inner chart. As such, much of the outer chart will not be repainted because it is not within that area.

    Your Paint event handler still draws the entire outer chart though. It's not for you to decide what to draw. You just draw everything. The system then decides what part of that drawing gets painted to the screen. It's that last step that is the slow part so it's that last step that has to be tightly controlled to pass as little data as possible.

    If you wanted to make the repaint even more efficient you could pass a Region when calling Invalidate instead of a Rectangle. You would create that Region from a GraphicsPath and you'd create the GraphicsPath from a circle. You could even then remove a smaller circle from the graphicsPath to create a doughnut shaped Region. That would be the absolute smallest area possible to repaint that contained your doughnut chart. While it's more complex, and therefore slower, to calculate that doughnut-shaped Region than it is to just use a Rectangle, it's faster to paint just the pixels in that area to the screen, so overall it's still more efficient to do it that way. I'll leave that to you as an exercise.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  17. #17

    Thread Starter
    Member
    Join Date
    Apr 2008
    Posts
    40

    Re: VB.net Doughnut Piecharts

    Hi

    In this below code
    I have 3 circle
    the innermost circle say circle1
    the 2nd inner most circle circle2
    the outermost circle circle3 (just default empty circle)

    whenever I draw circle2 I have to redraw circle1
    whenever I draw circle3 I have to redraw both circle2 and circle1 in that order.


    When I draw circle3 the problem is to retain the parts of circle2 (circle 1 is an empty circle with no pie parts)

    Every time a new pie part is added to the circle2 I save it in a collection
    In case of drawing circle3
    I draw circle 3 first then for I redraw the circle2 by retrieving the color,start,sweep angle attributes of the circle2. After drawing circle2 I draw circle1.

    But it gives an unexpected result. This functions partially.I hope the logic is right but the implementation is going wrong somewhere. Still certain part on circle1 and circle2 is overdrawn while drawing circle3.

    Please let me know where Am I going wrong. I just added hardcoded it to add 1 pie part for circle2 and another pie part for circle3

    Code:
    Public Class Form1
    
        Dim myPen As Pen = Pens.Brown 'New a Pen object   
        Dim part As DoughnutChartPart
        Dim parts As DoughnutChartPartCollection
        Dim g As Graphics
        Dim chk As Boolean = False
        Dim colors As Color
        Dim startAngle As Single
        Dim sweepAngle As Single
    
    
    
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    
            parts = New DoughnutChartPartCollection
            g = Me.PictureBox1.CreateGraphics()
    
            
        End Sub
    
        Private Sub PictureBox1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles PictureBox1.Click
            Me.Invalidate()
        End Sub
    
        
        Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
           
    
        End Sub
    
        Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
            g.DrawEllipse(myPen, 50, 50, 50, 50)
            g.DrawEllipse(myPen, 38, 38, 75, 75)
            g.DrawEllipse(myPen, 25, 25, 100, 100)
            DrawInner()
            DrawOuter()
        End Sub
        Private Sub DrawInner()
            'MessageBox.Show("Inner")
            If chk = False Then
                part = New DoughnutChartPart(Color.Red, 0, 45)
                g.DrawPie(New Pen(Color.Red), 38, 38, 75, 75, 0, 45)
                parts.Add(part)
            Else
                'MessageBox.Show(parts.Count.ToString)
                g.DrawPie(New Pen(Control.DefaultBackColor), 38, 38, 75, 75, 0, 360.0F)
                g.DrawEllipse(myPen, 38, 38, 75, 75)
                For Each part In Me.parts
                    g.DrawPie(New Pen(part.Colour), 38, 38, 75, 75, part.Start, part.Sweep)
                    'MessageBox.Show(part.Colour.ToString)
                    ' MessageBox.Show(part.Start.ToString)
                    'MessageBox.Show(part.Sweep.ToString)
                Next
            End If
            g.DrawPie(New Pen(Control.DefaultBackColor), 50, 50, 50, 50, 0, 360.0F)
            g.DrawEllipse(myPen, 50, 50, 50, 50)
        End Sub
        Private Sub DrawOuter()
    
            ' MessageBox.Show("Outer")
            g.DrawPie(Pens.Black, 25, 25, 100, 100, 0, 60)
            chk = True
            DrawInner()
            chk = False
        End Sub
    End Class
    
    Public Class DoughnutChartPart
        Private _colour As Color
        Private _text As String
        Private _value As Single
        Private _start As Single
        Private _sweep As Single
    
       
        Public Property Colour() As Color
            Get
                Return Me._colour
            End Get
            Set(ByVal value As Color)
                Me._colour = value
            End Set
        End Property
    
        Public Property Text() As String
            Get
                Return Me._text
            End Get
            Set(ByVal value As String)
                Me._text = value
            End Set
        End Property
    
        Public Property Start() As Single
            Get
                Return Me._start
            End Get
            Set(ByVal value As Single)
                If value < 0.0 Then
                    Me._start = 360 + value
                Else
                    Me._start = value
                End If
    
            End Set
        End Property
    
        Public Property Sweep() As Single
            Get
                Return Me._sweep
            End Get
            Set(ByVal value As Single)
                If value < 0.0 Then
                    Me._sweep = 360 + value
                Else
                    Me._sweep = value
                End If
            End Set
        End Property
    
        Public Sub New()
    
        End Sub
    
        Public Sub New(ByVal color As Color, _
                       ByVal start As Single, ByVal sweep As Single)
    
            Me._colour = color
            Me._sweep = sweep
            Me._start = start
    
        End Sub
    
    End Class
    
    Public Class DoughnutChartPartCollection
        Inherits System.Collections.ObjectModel.Collection(Of DoughnutChartPart)
    End Class

  18. #18

    Thread Starter
    Member
    Join Date
    Apr 2008
    Posts
    40

    Re: VB.net Doughnut Piecharts

    Thanks to all especially jmcilhinney. It works

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width