VB.NET Tips / Tricks / Examples and Help

VB.NET Dynamic Grid Drawings

Someone had posted a question about creating 1500 picturebox controls on a form for the purpose of some sort of game. Creating 1500 controls on a single form is always a recipe for disaster. I wrote them up an example on how you can do this by dynamically drawing on the form. You can still respond to things like the boxes being clicked, even if they aren't actual controls.

I figured I would share the code here. The example is basically a really primitive pixel art creator. It illustrates specifying a dynamic size of the grid in number of boxes, as well as the size of the boxes. You can shift the grid around the form with the arrow keys, and left clicks fill in each square with the selected color, while right clicks erase. Mouse overs on the squares will change the mouse cursor to the hand image. There is also code to fill each square with numbers, but remember, this isn't an example to make a program, but more to show you what can be done with this type of dynamic form painting.

I created these simple pixel are to show what the code can do.

 

As to the code, you can paste this into a WinForm and run.

 

    '****************************

    'SET THESE TO CHANGE THE GRID

    '****************************

    Private GridStartX As Integer = 100

    Private GridStartY As Integer = 100

    Private Const TotalSquares As Integer = 1500

    Private Const SquaresPerRow As Integer = 50

    Private Const SquareEdgeLength As Integer = 25

    Private BackgroundBrush As New SolidBrush(Color.LightGray) 'background color

    Private CurrentClickColor As New SolidBrush(Color.LightGreen) ' default click color

    Private TextFont As New Font(Me.Font.FontFamily, 6) 'font when drawing text in squares

    Private ShowNumbers As Boolean = False 'shows numbers on each square

 

    'LIST OF SQUARE OBJECTS

    Private Squares As List(Of SquareItem) = Nothing

 

    'SQUARE OBJECT CLASS

    'CONTAINS THE RECTANGLE OF THE SQUARE

    'IF IT IS ON OR OFF

    'WHAT COLOR 'ON' IS

    Private Class SquareItem

        Property Bounds As Rectangle

        Property Clicked As Boolean

        Property ClickedColor As Color

    End Class

 

    Private GridShift As Integer = 10

    Protected Overrides Function ProcessCmdKey(ByRef msg As System.Windows.Forms.Message, keyData As System.Windows.Forms.Keys) As Boolean

        Select Case keyData

            Case Keys.Left : AdjustGridPosition(-GridShift, 0)

            Case Keys.Right : AdjustGridPosition(GridShift, 0)

            Case Keys.Up : AdjustGridPosition(0, -GridShift)

            Case Keys.Down : AdjustGridPosition(0, GridShift)

        End Select

 

        Return MyBase.ProcessCmdKey(msg, keyData)

 

    End Function

 

    Private Sub AdjustGridPosition(OffsetX As Integer, OffsetY As Integer)

        For Each square In Squares

            square.Bounds = New Rectangle(New Point(square.Bounds.X + OffsetX, square.Bounds.Y + OffsetY), square.Bounds.Size)

        Next

        Me.Invalidate()

    End Sub

 

    'GENERATES THE GRID INTO A LIST OF SQUARE OBJECTS, BASED ON THE VALUES ABOVE

    Private Sub CreateGrid()

        Squares = New List(Of SquareItem)

        Dim SquareSpacing As Integer = 0

        Dim TotalRows = TotalSquares \ SquaresPerRow 'just assuming we will get even division here, wouldn't normally do this

        Dim SquareSize As New Size(SquareEdgeLength, SquareEdgeLength)

        Dim RowPoint As Integer = GridStartX

        Dim ColPoint As Integer = GridStartY

        For i As Integer = 1 To TotalRows

            ColPoint = GridStartX

            For j As Integer = 1 To SquaresPerRow

                Dim loc As New Point(ColPoint, RowPoint)

                Dim rect As New Rectangle(loc, SquareSize)

                Squares.Add(New SquareItem With {.Bounds = rect})

                ColPoint += (SquareEdgeLength + SquareSpacing)

            Next

            RowPoint += (SquareEdgeLength + SquareSpacing)

        Next

    End Sub

 

    'DRAWS THE GRID ONTO THE FORM

    Private Sub DrawGrid(g As Graphics)

        Dim SquareCount As Integer = 1

        Dim SF As New StringFormat() With {.Alignment = StringAlignment.Center, .LineAlignment = StringAlignment.Center}

        For Each Square In Squares

            g.FillRectangle(If(Square.Clicked, New SolidBrush(Square.ClickedColor), BackgroundBrush), Square.Bounds)

            g.DrawRectangle(Pens.Black, Square.Bounds)

            If ShowNumbers Then

                g.DrawString(SquareCount.ToString, TextFont, Brushes.Black, Square.Bounds, SF)

            End If

            SquareCount += 1

        Next

    End Sub

 

    Public Sub New()

 

        ' This call is required by the designer.

        InitializeComponent()

 

        ' Add any initialization after the InitializeComponent() call.\

 

        'SETUP SOME INITIAL FORM VALUES

        Me.DoubleBuffered = True

        Me.WindowState = FormWindowState.Maximized

        Me.BackColor = Color.White

 

        'CREATE A BUTTON FOR COLOR SELECTIONS

        Dim ButtonColor As New Button

        AddHandler ButtonColor.Click, AddressOf ButtonColor_Click

        ButtonColor.Text = "Color"

        Me.Controls.Add(ButtonColor)

 

        'CREATE INITIAL GRID

        CreateGrid()

    End Sub

 

    'USE MOUSEMOVE TO DO SOMETHING LIKE CHANGE THE MOUSE CURSOR ON HOVER

    Private Sub Form1_MouseMove(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove

 

        Dim square = GetSquareAtPoint(e.Location)

        If square IsNot Nothing Then

            Me.Cursor = Cursors.Hand

        Else

            Me.Cursor = Cursors.Default

        End If

    End Sub

 

    'USE MOUSEUP EVENT TO SWITCH SQUARE CLICKED/UNCLICKED. INVALIDATE FORM TO REDRAW

    Private Sub Form1_MouseUp(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseUp

 

        Dim square = GetSquareAtPoint(e.Location)

        If square IsNot Nothing Then

            If e.Button = Windows.Forms.MouseButtons.Left Then

                square.Clicked = True

                square.ClickedColor = CurrentClickColor.Color

            Else

                square.Clicked = False

                square.ClickedColor = BackgroundBrush.Color

            End If

            Me.Invalidate()

        End If

 

    End Sub

 

    'CHECKS THE LIST OF SQUARES FOR ONE THAT FALLS WITHIN THE PASSED IN POINT

    Private Function GetSquareAtPoint(pt As Point) As SquareItem

        For Each Square In Squares

            If Square.Bounds.Contains(pt) Then

                Return Square

            End If

        Next

        Return Nothing

    End Function

 

    'WHEN THE FORM DRAWS, REDRAW THE GRID

    Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint

        DrawGrid(e.Graphics)

    End Sub

 

    'BUTTON SETS THE CURRENT COLOR FOR CLICKS

    Private Sub ButtonColor_Click(sender As System.Object, e As System.EventArgs)

        Using CP As New ColorDialog

            CP.Color = CurrentClickColor.Color

            If CP.ShowDialog = Windows.Forms.DialogResult.OK Then

                CurrentClickColor.Color = CP.Color

            End If

        End Using

    End Sub


Posted Aug 08 2014, 06:15 AM by Matthew Kleinwaks
Filed under: ,


© 2014 - ZerosAndTheOne.com - Hosting by Orcsweb (http://www.orcsweb.com/)
Powered by Community Server (Non-Commercial Edition), by Telligent Systems