Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

CPT 341 VB.NET Project 5 GDI+, Bar Charting, Structures, Bitmap Object, ArrayLis

ID: 3692762 • Letter: C

Question

CPT 341 VB.NET Project 5 GDI+, Bar Charting, Structures, Bitmap Object, ArrayLists Develop a VB.NET project, using GDI+ (Graphic Device Interface ) to draw a bar chart. The x-axis will represent a country and a y-axis will represent sales data Notes: . Use the GDI+ libraries to create 2-D graphic primitives » Use a Picture Box control to display a Bitmap image of the bar chart » Set appropriate margins, gaps, and scaling where the bitmap bar chart scales if the picture box control orientation changes » Use an ArrayList to store the country and population data (you can make these numbers up) » Use a Structure to declare sales data and country data Example Output 1000 900 800 500 400 300 200 100 Belgium Greece Portugal Spain Turkey UK Project 5 Submit Date: 4/11/2016 Class Due Date: 4/25/2016 Note: Send all completed VB Project files to: wxt1955@njit.edu (or use Dropbox, Google Docs, etc.)

Explanation / Answer

Step 1: Generate the Data
Data Content   
    For continuity’s sake we will use a Structure and an ArrayList for the data because this is the approach we used in Part 1.

Put these Statements at the very top of the form:

    Option Strict On
    Imports System.Drawing.Drawing2D
    Imports System.Collections

   Create a Structure similar to that used in Part 1 (placed in the Form’s code area, but outside any procedures):

    Structure GraphData
        Dim Country As String
        Dim Sales As Short
        Sub New(ByVal country As String, ByVal sales As Short)
            Me.Country = country
            Me.Sales = sales
        End Sub
    End Structure

Instantiate an ArrayList to hold the data. Again, place this in the form’s code area, outside any procedures:

   Dim SalesData As New ArrayList

    The GetData procedure generates some sample data: six countries and six sales figures.   (Looking ahead, in Part 3 we will see how to replace this with code which reads data from file or takes input from the user.)

   Private Sub GetData()

   SalesData.Clear()
   ' Ensure that only one set of generated data is held
        SalesData.Clear()
   ' Generate some data and store it in the arraylist
        SalesData.Add(New GraphData("Belgium", 834))
        SalesData.Add(New GraphData("Greece", 385))
        SalesData.Add(New GraphData("Portugal", 672))
        SalesData.Add(New GraphData("Spain", 429))
        SalesData.Add(New GraphData("Turkey", 715))
        SalesData.Add(New GraphData("UK", 942))    
End Sub


   We now have some data to use to create our chart.

Step 2: Get Control

The chart will be displayed in a PictureBox and the drawing will be fired by the click of a button. Time then to add these controls to the form.

   Add a PictureBox control on to the form and name it PBBarChart. Cover approx 80% of the form with the PictureBox.    Then add a Button control somewhere in the remaining surface of the form and name this btnDraw
Set the backcolor of the Form to a light color of your choice.

    We are ready to begin creating the chart.

Step 3: Set the Margins, Gaps and Scaling

The chart will be drawn inside a PictureBox, so we should create a margin between the chart itself and the outer edges of the PictureBox.    We will use four variables to hold these values. The names are self-explanatory:

' # of pixels Y-Axis is inset from PicBox Left
    Dim LeftMargin As Integer = 35
    ' # of Pixels left unused at right side of PicBox
    Dim RightMargin As Integer = 15
    ' # of pixels above base of picturebox the X-Axis is placed
    Dim BaseMargin As Integer = 35
    ' Margin at Top
    Dim TopMargin As Integer = 10

When we come to draw the bars of the chart, they will look better with a small gap between them. The next variable contains that setting:

    Dim BarGap As Integer = 12

Draw The Chart : Verticals

Step 4a: Graphics and Bitmap Objects

   All the drawing code goes into one procedure named DrawChart. Here is the code for the above actions (This is of course just the first part of the complete procedure):

Private Sub DrawChart()
   Dim g As Graphics
   Dim bmap As Bitmap
   bmap = New Bitmap(PBBarChart.Width, PBBarChart.Height, _
           PBBarChart.CreateGraphics)
   g = Graphics.FromImage(bmap)

Step 4b: Vertical Axis

     Dim StartPoint As New Point(LeftMargin, PBBarChart.Height - BaseMargin)
   Dim EndPoint As New Point(LeftMargin, TopMargin)

   Armed with our start and end points, we take a pen and draw the line:

    Dim LinePen As New Pen(Color.Black, 2)
   g.DrawLine(LinePen, StartPoint, EndPoint)

    Dim VertLineLength As Integer = PBBarChart.Height - (BaseMargin + TopMargin)

This will enable us to calculate the correct gap between each of the Ticks. The layout is from 0 to 1000 in intervals of 100, remember:

   Dim VertGap As Integer = CInt(VertLineLength / 10)
       
    I have arbitrarily chosen to set the (horizontal) length of each Tick mark as 5 pixels.   It follows then that the start point of each Tick must be 5 pixels to the left of the vertical axis.   The end point of each Tick will be on the vertical axis itself. Those are the x positions needed and are the same for each Tick.

   The y positions (which you will recall are the number of pixels counting down from the top) must change for each Tick mark, because we are drawing ten of them equally spaced all the way up the vertical axis.   The spacing between them therefore must be the value we have just calculated – VertGap.

  Dim TickSP As New Point(LeftMargin - 5, StartPoint.Y - VertGap)
  Dim TickEP As New Point(LeftMargin, StartPoint.Y - VertGap)

We have all the information needed to create the Tick marks and the 100, 200, 300, etc text.   Let’s set up a Font for the text:

  Dim ValueFont As New Font("Arial", 8, FontStyle.Regular)
      
And now we can loop 10 times through a code block which will draw out Tick marks from bottom to top and add the 100s as text at the same time:

  For i As Integer = 1 To 10
   ' Tick mark
   g.DrawLine(New Pen(Color.Black), TickSP, TickEP)
   ' Tick Values as text
   g.DrawString(CStr(i * 100), ValueFont, Brushes.Black, 2, TickSP.Y - 5)
   ' Reset y positions, moving 10% up vertical line
   TickSP.Y -= VertGap
   TickEP.Y -= VertGap
Next

Step 4d: Time For A Test
    
    Although we have more drawing code to write before we are done, it might be useful to fast-forward and have a look at the results so far.   To do this, add the following code to the very end of the DrawChart Sub:

          PBBarChart.Image = bmap
     g.Dispose()
     LinePen.Dispose()
    End Sub

I will explain this code later, but for now it will enable you to run the project and see the vertical axis and the Tick marks.  Just be sure to remember that the code we create in the following pages is entered above those three lines, otherwise there will be problems.

   The button is used to fire the drawing code, so the button_click event of btnDraw needs to call the two procedures we have created:

    Private Sub btnDraw_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDraw.Click
        ' Generate the Data
        GetData()
        ' Then Draw the Chart
        DrawChart()
   End Sub

  You may be thinking that this isn’t much to show for several pages of explanation.   Bear in mind though that the actual code used is really quite short.   Because this series of articles is aimed squarely at graphics newbies, I’ve erred on the side of too much explanation, rather than too little.  


     


  

Draw The Chart: Horizontals

Step 5: Horizontal Axis and the Bars

5a. Base Line
The logic for the Horizontal (X) Axis is similar to that used to draw and measure the Vertical Axis:

  ' First draw the X (horizontal) axis line
g.DrawLine(LinePen, LeftMargin, PBBarChart.Height - BaseMargin, _
     PBBarChart.Width - RightMargin, PBBarChart.Height - BaseMargin)
' Calculate length of baseline drawn by the code above
  Dim BaseLineLength As Integer = _
     PBBarChart.Width - (LeftMargin + RightMargin)

5b. The Bars
     Calculating the width of each bar again is simple math: Divide the length of the baseline by the number of bars (which is the same as the number of elements in the SalesData arraylist – one per country). Subtract the width you decided earlier to insert between bars.  

   Dim BarWidth As Double = (BaseLineLength / SalesData.Count) - BarGap

    Each bar is of course rectangular, so we will create a Rectangle object for this purpose.   To locate the X-position of the first bar we start at the intersection of the x and y axis and then move to the right a distance equal to the width we decided to insert between bars.      The Y-position is set one pixel above the baseline:

  Dim BarRect As Rectangle
  Dim BarStartX As Integer = LeftMargin + BarGap
  Dim BarStartY As Integer = PBBarChart.Height - (BaseMargin + 1)

Next, create a brush with which to draw and fill the bar rectangles:

   Dim BarBrush As New SolidBrush(Color.BurlyWood)

So much for the width. Now we need to consider the heights of the bars. Obviously the height of each bar will represent the sales figure for a country.   We have already configured the vertical axis so that it is marked out to a maximum of 1000 units of sales values.

   The vertical axis also has another value – the number of pixels that make up its length.      In order to ensure that each bar’s height is drawn proportionately to the total pixels available we must calculate the scale, i.e. how many Sales are represented by a single pixel up that vertical line.    This measurement will be used to ensure that the bars are drawn proportionately within the overall height available for them.

   This may sound complicated. It really isn’t and the calculation itself is very simple:

    Dim VertScale As Double
   VertScale = VertLineLength / 1000  

   By enumerating through the information stored in the arraylist, we can pull out the sales figures one after the other.   We use this figure to calculate the height of the bar .
   
There are several ways of approaching the task of drawing the bars in the correct positions, some easier than others.    The approach I have taken for this article is as follows. For each bar:-

   And here is the code which does exactly that:

  For Each gd As GraphData In SalesData
    ' Calculate Bar Height
    Dim BarHeight As Integer = CInt(gd.Sales * VertScale)
    ' Create a rectangle for the Bar
    BarRect = New Rectangle(BarStartX, BarStartY, CInt(BarWidth), _
          BarHeight)
    ' Pull the Y point upwards so that the bar (rectangle) will
    ' stretch back down to the baseline when drawn
    BarRect.Offset(0, -BarHeight)
    ' Fill the Bar
    g.FillRectangle(BarBrush, BarRect)
    ' Optionally draw a line round the bar
    g.DrawRectangle(LinePen, BarRect)
    ' Increase the X value by bar width plus gap
    ' ready for next bar to be drawn.
    BarStartX += CInt(BarWidth + BarGap)
Next

5c.   Country Names

The names of the countries are displayed at the bottom of each bar.   In a later article we will investigate more challenging and pictorial ways of doing this but for now simple text using DrawString will suffice.

As the process is similar to those we have used already in this project, the commented code will, I hope, make sense to you at this stage:

   ' Set the start point of the first string
   Dim TextStartX As Integer = LeftMargin + BarGap + 4

   ' Create a Brush to draw the text
   Dim TextBrsh As Brush = New SolidBrush(Color.Black)
   ' Create a Font object instance for text display
   Dim TextFont As New Font("Arial", 11, FontStyle.Bold)

   For Each gd As GraphData In SalesData
       ' Draw the name of the country
       g.DrawString(gd.Country, TextFont, TextBrsh, TextStartX, _
          CInt(PBBarChart.Height - (BaseMargin - 4)))   
        ' Move start point along to the right
        TextStartX += CInt(BarWidth + BarGap)
   Next

All Is Revealed!

Step 6: All is Revealed!

  

' Assign the chart drawing bitmap as the image for the picturebox
PBBarChart.Image = bmap

      ' Dispose of drawing objects
        g.Dispose()
        LinePen.Dispose()
        BarBrush.Dispose()
        ValueFont.Dispose()
        TextFont.Dispose()
     End Sub

  Private Sub btnDraw_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDraw.Click
        ' Generate the Data
        GetData()
        ' Then Draw the Chart
        DrawChart()
    End Sub

Hire Me For All Your Tutoring Needs
Integrity-first tutoring: clear explanations, guidance, and feedback.
Drop an Email at
drjack9650@gmail.com
Chat Now And Get Quote