Lo scopo di questo tutorial è quello di mostrare come creare un semplice programma per la rappresentazione dei dati in un grafico a barre (istogrammi). Nell'esempio che segue vengono usati dei dati raccolti in un array, ciò non toglie che la fonte delle informazioni possa essere di altro genere (Dataset, DataGridView, TextBox...)
Avviamo un nuovo progetto Windows Application e impostiamo le seguenti proprietà del form:
Size:500;400 Text:Grafico a Barre
Inseriamo anche una PictureBox:
Anchor:Top, Bottom, Left, Right Dock:Fill BackColor:White
Dichiariamo un array, DatiGrafico, in cui inseriamo 12 valori single, e una variabile integer, NumeroValori, che contiene il numero di elementi dell'array.
Public Class Form1 Dim datiGrafico() As Single = {120, 98, 69, 78, 236, 159, 64, 58, 169, 74, 211, 200} Dim numeroValori As Integer = 12
Adesso inseriamo una funzione per determinare il valore massimo fra quelli inseriti. Tale valore è utile per determinare la corretta scala del disegno in relazione alle dimensioni della form.
Private Function CalcolaMassimo(ByVal valore() As Single) As Single Dim risultato As Single = 0 For Each numero As Single In valore If numero > risultato Then risultato = numero Next Return risultato End Function
Adesso inseriamo il codice che disegna il grafico in base ai dati forniti:
Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) _ Handles PictureBox1.Paint Dim maxValore As Single = CalcolaMassimo(datiGrafico) If maxValore = 0 Then Exit Sub
la variabile maxValore contiene il valore calcolato dalla funzione descritta in precedenza.
La If...Then serve unicamente a impedire che venga disegnato un grafico nel caso in cui tutti i dati siano a zero. In questa situazione questa istruzione non ha alcun senso, ma può tornare utile nei casi in cui è necessario valutare il valore dei dati raccolti, e per evitare che venga disegnato un grafico in cui tutti i dati sono nulli.
Otteniamo l'oggetto Graphics attraverso il riferimento a PaintEventArgs. In questo caso non è necessario rilasciare le risorse usando il metodo Dispose.
Dim gr As Graphics = e.Graphics
Questa istruzione condizionale fa si che il valore massimo ritornato dalla funzione descritta all'inizio, venga arrotondato per eccesso al multiplo di 10 più prossimo.
Nel nostro esempio il valore maggiore è 236, dopo la If...Then diventa 240.
If (maxValore Mod 10) > 0 Then maxValore = (CType(maxValore, Long) \ 10) * 10 + 10 End If
Vengono definiti la penna con cui disegnare gli assi, il font per scrivere i valori e il pennello con cui colorare le barre del grafico.
Dim penBlack As New Pen(Color.Black, -1) Dim labelFont As New Font("Arial", 3, FontStyle.Regular) Dim ColoreTesto As New SolidBrush(Color.Blue)
Vengono definite le variabili che rappresentano gli angoli opposti dell'area grafica (x1;y1 e x2;y2), la dimensione delle scala lungo i due assi (scaleX e scaleY) e infine un rettangolo che rappresenta la barra da disegnare.
Dim x1, y1 As Single Dim x2, y2 As Single Dim scaleX, scaleY As Single Dim oneBar As RectangleF
angolo in alto a sinistra.
x1 = 10 y1 = 10
angolo in basso a destra.
x2 = numeroValori * 10 + 10 y2 = maxValore + 10
definizione della scala lungo i due assi.
scaleX = Me.PictureBox1.Width / (x2 + x1) scaleY = Me.PictureBox1.Height / (y2 + y1)
applicazione della scala lungo i due assi all'area grafica. scaleY risulta negativa per avere la direzione positiva dell'asse Y verso l'alto.
gr.ScaleTransform(scaleX, -scaleY)
traslazione dell'origine del sistema di riferimento alle nuove coordinate (x1;-y2).
gr.TranslateTransform(x1, -y2)
colora di bianco l'area grafica.
gr.Clear(Color.White)
disegna il rettangolo che rappresenta la zona ove saranno disegnate le barre.
gr.DrawRectangle(penBlack, New Rectangle(0, 0, 10 * numeroValori, CType(maxValore, Integer)))
disegna la griglia.
For xScan As Single = 10 To (numeroValori * 10 - 10) Step 10 gr.DrawLine(penBlack, xScan, 0, xScan, maxValore) Next xScan For yScan As Single = 10 To maxValore Step 10 gr.DrawLine(penBlack, 0, yScan, (numeroValori * 10), yScan) Next yScan
Disegna l'ombra delle barre del grafico.
For xScan As Single = 0 To numeroValori - 1 oneBar.X = CType(xScan * 10 + 0.6, Single) oneBar.Y = 0 oneBar.Width = 6 oneBar.Height = datiGrafico(CType(xScan, Integer)) gr.FillRectangle(New SolidBrush(Color.FromArgb(127, Color.Gray)), oneBar)
Disegna la barra che rappresenta il valore nell'array nella posizione specificata.
oneBar.X = xScan * 10 + 2 oneBar.Y = 0 oneBar.Height = datiGrafico(CType(xScan, Integer)) gr.FillRectangle(New SolidBrush(Color.DarkOrange), oneBar) Next xScan
Cancella tutte le trasformazioni per disegnare i valori lungo gli assi, altrimenti sarebbero rappresentati capovolti a causa delle modifiche effettuate per avere l'origine in basso a sinistra e il verso positivo dell'asse Y rivolto in alto.
gr.ResetTransform()
applica la scala all'area grafica.
gr.ScaleTransform(scaleX, scaleY)
applica la traslazione dell'origine.
gr.TranslateTransform(x1, y1)
disegna i valori di riferimento lungo gli assi cartesiani.
For yScan As Single = 0 To maxValore Step 10 gr.DrawString(yScan.ToString, labelFont, ColoreTesto, -2 * yScan.ToString.Length - 3, maxValore - 3 - yScan) Next yScan For xScan As Single = 0 To numeroValori * 10 Step 10 gr.DrawString(xScan.ToString, labelFont, ColoreTesto, CType(xScan + 1.7 - 2 * xScan.ToString.Length, Single), _ CType(maxValore + 3, Single)) Next xScan
rilascia le risorse occupate dal font, dalla penna e dal pennello.
labelFont.Dispose() ColoreTesto.Dispose() penBlack.Dispose() gr = Nothing End Sub
Qualora la form subisca un cambiamento delle dimensioni, anche la PictureBox, ad essa ancorata subirà una variazione dell'altezza e lunghezza, pertanto nell'evento Resize della form inseriamo il comando Refresh per ri-disegnare l'area grafica e adattarla ai nuovi valori.
Private Sub Form1_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Resize Me.Refresh() End Sub End Class
Ecco il risultato: