Displaying the Data
You may have started to wonder how I managed to generate
those nifty little graphs at the bottom of the last four pages.
Well, I'm going to tell you. I created a UserControl that
completely separates the algorithm logic, and the painting logic.
The painting logic is the same no matter what algorithm was used to
generate the Bins.
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
Private Function DrawDemarcations() As Integer
Dim TextHeight As Integer = CType(g.MeasureString(Me.BinHeight.ToString, DrawingFont).Height, _
Integer)
g.DrawString(Me.BinHeight.ToString, DrawingFont, DrawingTextBrush, BORDER, BORDER - 8)
g.DrawString((Me.BinHeight * 0.75).ToString, DrawingFont, DrawingTextBrush, BORDER, _
CType((Me.Height - BORDER * 2) * 0.25, Integer) + BORDER - TextHeight + 6)
g.DrawString((Me.BinHeight * 0.5).ToString, DrawingFont, DrawingTextBrush, BORDER, _
CType((Me.Height - BORDER * 2) * 0.5, Integer) + BORDER - TextHeight + 6)
g.DrawString((Me.BinHeight * 0.25).ToString, DrawingFont, DrawingTextBrush, BORDER, _
CType((Me.Height - BORDER * 2) * 0.75, Integer) + BORDER - TextHeight + 6)
g.DrawString("0", DrawingFont, DrawingTextBrush, BORDER, Me.Height - BORDER - TextHeight + 5)
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
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
If i < Bins.GetUpperBound(0) + 1 Then
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
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
g.DrawLine(DrawingPen, X1, Y1, X2, Y2)
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
g.DrawString((i + 1).ToString, DrawingFont, DrawingTextBrush, _
CType(X1 + (BIN_WIDTH / 2) - (g.MeasureString((i + 1).ToString, _
DrawingFont).Width / 2), Integer), Me.Height - BORDER)
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
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.