The code really is self explanatory and comes with comments. This demonstrates the proper way to display process intensive visual data. Notice that actual drawing is done only when needed. When a Paint event is fired, the control is merely refreshing itself with a cached Bitmap. This cuts way down on processing time and is really the correct way of doing things.
Private Sub UpdateGraph()
InitDrawingSurface()
DrawBins(DrawDemarcations())
pbDrawingSurface.Refresh()
End Sub
Private Sub InitDrawingSurface()
If Me.Width = 0 Or Me.Height = 0 Then Exit Sub
bmpGraph = New Bitmap(Me.Width, Me.Height)
g = Graphics.FromImage(bmpGraph)
g.Clear(Me.BackColor)
pbDrawingSurface.Size = bmpGraph.Size
End Sub
'Returns how wide the text was on the left hand side of the graph as well as draws teh Demarcations
Private Function DrawDemarcations() As Integer
Dim TextHeight As Integer = CType(g.MeasureString(Me.BinHeight.ToString, DrawingFont).Height, _
Integer)
'100% of BinHeight
g.DrawString(Me.BinHeight.ToString, DrawingFont, DrawingTextBrush, BORDER, BORDER - 8)
'75% of BinHeight
g.DrawString((Me.BinHeight * 0.75).ToString, DrawingFont, DrawingTextBrush, BORDER, _
CType((Me.Height - BORDER * 2) * 0.25, Integer) + BORDER - TextHeight + 6)
'50% of BinHeight
g.DrawString((Me.BinHeight * 0.5).ToString, DrawingFont, DrawingTextBrush, BORDER, _
CType((Me.Height - BORDER * 2) * 0.5, Integer) + BORDER - TextHeight + 6)
'25% of BinHeight
g.DrawString((Me.BinHeight * 0.25).ToString, DrawingFont, DrawingTextBrush, BORDER, _
CType((Me.Height - BORDER * 2) * 0.75, Integer) + BORDER - TextHeight + 6)
'0% of BinHeight
g.DrawString("0", DrawingFont, DrawingTextBrush, BORDER, Me.Height - BORDER - TextHeight + 5)
'If there's decimals, Width2 will be longer, else, Width1 will be
Dim Width1 As Integer = CType(g.MeasureString(Me.BinHeight.ToString, DrawingFont).Width, Integer)
Dim Width2 As Integer = CType(g.MeasureString((Me.BinHeight * 0.75).ToString, _
DrawingFont).Width, Integer)
Return Math.Max(Width1, Width2) + 5 + BORDER
End Function
Private Sub DrawBins(ByVal StartX As Integer)
Dim BinPixelHeight As Integer = Me.Height - BORDER * 2
Dim X1, X2, Y1, Y2 As Integer
Dim i As Integer
Y1 = BORDER
Y2 = Me.Height - BORDER
If Bins Is Nothing Then Exit Sub
'Draws the vertical lines that make up the bins
For i = 0 To Bins.GetUpperBound(0) + 1
X1 = StartX + (BIN_WIDTH * i)
X2 = X1
g.DrawLine(DrawingPen, X1, Y1, X2, Y2)
Next
Dim j As Integer
Dim BinValue As Integer
Dim TotalBinHeight, TotalPixelBinHeight As Integer
For i = 0 To Bins.GetUpperBound(0) + 1
X1 = StartX + (BIN_WIDTH * i)
X2 = X1 + BIN_WIDTH
'Draws the Bins
If i < Bins.GetUpperBound(0) + 1 Then
'Draws the gradient
TotalBinHeight = 0
For j = 0 To Bins(i).GetUpperBound(0)
TotalBinHeight += Bins(i)(j)
Next
TotalPixelBinHeight = CType(TotalBinHeight / Me.BinHeight * BinPixelHeight, Integer)
If TotalPixelBinHeight > 0 Then
'Draws the Bin gradient
DrawingBinBrush = New LinearGradientBrush(New Rectangle(X1 + 1, Me.Height - _
BORDER - TotalPixelBinHeight, BIN_WIDTH - 1, TotalPixelBinHeight), _
Me.BinColor1, Me.BinColor2, LinearGradientMode.ForwardDiagonal)
DrawingBinBrush.WrapMode = WrapMode.TileFlipXY
g.FillRectangle(DrawingBinBrush, New Rectangle(X1 + 1, Me.Height - BORDER - _
TotalPixelBinHeight, BIN_WIDTH - 1, TotalPixelBinHeight))
Dim LastY As Integer
For j = 0 To Bins(i).GetUpperBound(0)
BinValue += Bins(i)(j)
Y1 = CType(BinValue / Me.BinHeight * BinPixelHeight, Integer)
Y1 = Me.Height - Y1 - BORDER
Y2 = Y1
If j = 0 Then LastY = Me.Height - BORDER
'Draws the horizontal lines
g.DrawLine(DrawingPen, X1, Y1, X2, Y2)
'Draws the Element value
Dim TextSize As SizeF = g.MeasureString(Bins(i)(j).ToString, DrawingFont)
g.DrawString(Bins(i)(j).ToString, DrawingFont, Me.DrawingBinTextBrush, _
CType(X1 + (BIN_WIDTH / 2) - (TextSize.Width / 2), Integer), _
CType(Y1 + ((LastY - Y1) / 2) - (TextSize.Height / 2), Integer))
LastY = Y1
Next
'Draws the Bin Number
g.DrawString((i + 1).ToString, DrawingFont, DrawingTextBrush, _
CType(X1 + (BIN_WIDTH / 2) - (g.MeasureString((i + 1).ToString, _
DrawingFont).Width / 2), Integer), Me.Height - BORDER)
'Draws the Bin Count
g.DrawString(TotalBinHeight.ToString, DrawingFont, DrawingBinTextBrush, _
CType(X1 + (BIN_WIDTH / 2) - (g.MeasureString(TotalBinHeight.ToString, _
DrawingFont).Width / 2), Integer), 5)
BinValue = 0
End If
End If
Next
'Bottom line
g.DrawLine(DrawingPen, StartX, Me.Height - BORDER, X1, Me.Height - BORDER)
End Sub
Complete code may be found as a Resource, downloadable at the top of any page.
Comments