Visualizing LINQ Sequences with GDI+, Page 2
The utility is capable of producing rectangle sub-divisions as suggested by the roughly created grid in the comment in the first part of the listing. You can specify the number of vertical and horizontal sub-rectangles, which horizontal and vertical sub-rectangle to return, and CenterRect (at the end) will return a rectangle centered vertically and horizontally within another rectangle.
The reason shared methods were used is that the Rectangles class itself stores no data; that is, it contains no fields, properties, or events. Following a general OOP rule such a class is naturally specified as a class containing all shared members.
Defining a State-Full Rectangle Manager
Next, I wanted to able to track individual rectangles, so a state-full RectangleManager was defined. This class keeps track of its horizontal and vertical sub-rectangles (with hSegments and vSegments), the desired padding between rectangles, and the original outer rectangle. This class is useful for keeping track of a specific rectangle set being used. Listing 2 contains the RectangleManager.
Listing 2: The RectangleManager is state-full—keeping track of the rectangle under management.
Imports System.Collections Public Class RectangleManager 'Implements IEnumerator ' note to self - implement IEnumerator so we can do a foreach ' over the segments Public Sub New(ByVal Rect As Rectangle, _ ByVal hSegments As Integer, ByVal vSegments As Integer) Me.Rect = Rect Me.vSegments = vSegments Me.hSegments = hSegments End Sub Public Sub New(ByVal Rect As Rectangle, _ ByVal hSegments As Integer, _ ByVal vSegments As Integer, ByVal padding As Integer) Me.Rect = Rect Me.vSegments = vSegments Me.hSegments = hSegments Me.padding = padding End Sub Private Rect As Rectangle Private vSegments As Integer Private hSegments As Integer Private padding As Integer = 4 Public Function GetSubRect(ByVal xSegment As Integer, _ ByVal ySegment As Integer) As Rectangle Return Rectangles.GetSubRect(Rect, xSegment, ySegment, _ hSegments, _ vSegments, padding) End Function Public Function CenterRect(ByVal size As SizeF, _ ByVal xSegment As Integer, _ ByVal ySegment As Integer) Return Rectangles.CenterRect(size, GetSubRect(xSegment, _ ySegment)) End Function End Class
Visualizing a LINQ Query with the Rectangle Manager
A LINQ query returns a sequence. (Think collection!) By using ellipses, you can visualize the sequence as a linear row of circles with each circle containing the text (or a representation of the text) in the circle itself. Listing 3 shows the form for representing the sequence visually, and Listing 4 contains a concrete behavior class that contains the draw-sequence behavior. (You can look up the State Behavior Pattern on dofactory.com or the GoF book on Design Patterns.)
Listing 3: The Form using a state behavior pattern; the Form shows the visual representation of the LINQ query.
Public Class Form1 Private state As MyStatePattern Private Sub Form1_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load state = New DrawSequenceState(p) End Sub Private p As Pen = New Pen(Color.Red, 4) Private Sub Form1_Paint(ByVal sender As Object, _ ByVal e As System.Windows.Forms.PaintEventArgs) _ Handles Me.Paint state.Draw(e.Graphics, Font) End Sub Private Sub DrawRectanglesToolStripMenuItem_Click(ByVal _ sender As System.Object, _ ByVal e As System.EventArgs) Handles _ DrawRectanglesToolStripMenuItem.Click state = New DrawRectState(p) Invalidate() End Sub Private Sub DrawEllipsesToolStripMenuItem_Click(ByVal sender _ As System.Object, _ ByVal e As System.EventArgs) Handles _ DrawEllipsesToolStripMenuItem.Click state = New DrawEllipseState(p) Invalidate() End Sub Private Sub DrawSequenceToolStripMenuItem_Click(ByVal sender _ As System.Object, _ ByVal e As System.EventArgs) Handles _ DrawSequenceToolStripMenuItem.Click state = New DrawSequenceState(p) Invalidate() End Sub End Class