Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
692 views
in Technique[技术] by (71.8m points)

vb.net - Grid I can paint on

So I am trying to create an application to ease creation of pixel arts (school project), what I've done so far is draw a grid in a panel, next step would be to allow the user to click on a cell and have it painted, but I can't manage to make it work, here's the code I have:

Private Sub drawGrid(g As Graphics, rows As Integer, columns As Integer)

    Dim originPoint As Point = New Point(10, 2)
    Dim size As Size = New Size(64, 64)
    Dim left As Integer = originPoint.X
    Dim up As Integer = originPoint.Y
    Dim right As Integer = originPoint.X + (columns * size.Width)
    Dim down As Integer = originPoint.Y + (rows * size.Height)
    For y As Integer = up To down + 1 Step size.Height
        Dim pt1 As New Point(left, y)
        Dim pt2 As New Point(right, y)
        g.DrawLine(Pens.Black, pt1, pt2)
    Next
    For x As Integer = left To right + 1 Step size.Width
        Dim pt1 As New Point(x, up)
        Dim pt2 As New Point(x, down)
        g.DrawLine(Pens.Black, pt1, pt2)
    Next

End Sub

This draws a grid with the amount of columns and rows the user wants, but I've been struggling to allow painting

What I've been thinking is: dispose this code, and create a 'pixel' class, create the amount of 'pixel' objects based on user rows and columns, and draw each one individually, then just change each 'pixel's' color

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This is a Grid class that allows setting the color of its cells.

The Grid cell are referenced using a List(Of List(Of Class)).

The Cell class Object contains is a simple Rectagle property that measures the size of the cell, and a Color property, which allows to set the color of the single cell:

Friend Class GridCell
    Public Property Cell() As Rectangle
    Public Property CellColor() As Color
End Class

You can define:

  • The size of the Grid → ColoredGrid.GridSize = new Size(...)
  • The number of Columns and Rows → ColoredGrid.GridColumnsRows = new Size(...)
  • The position of the Grid inside the CanvasColoredGrid.GridPosition = New Point(...)
  • The color of the Grid → ColoredGrid.GridColor = Color.Gray
  • The BackGround color of the cells → ColoredGrid.CellColor = Color.FromArgb(32, 32, 32)
  • The color of a selected cell → ColoredGrid.SelectedCellColor = Color.OrangeRed


The Grid class holds a reference to the control which will be used as the Canvas for the grid painting. This reference is set in the class contructor.
The Grid registers the Canvas control Paint() and MouseClick() events to respond to the related actions automatically.
When a Mouse Click is detected on the Canvas surface, the MouseEventArgs e.Location property reports the coordinates where the Click occurred.

To identify the Grid Cell where this action is performed, the GetUpdateCell() method inspects the List(Of List(Of GridCell)) using a simple LINQ SelectMany() and identified the Cell rectangle that contains the Mouse Click coordinates (expressed as a Point() value).
This identification is performed simply checking whether the Cell Rectangle.Contains(Point()).
When the cell is identified, the Canvas Invalidate() method is called, specifing the area to repaint.
This area corresponds to the Cell Rectangle, so only this section is repainted when a Cell is colored, to save resources and time.

To test it, create a Panel and a Button in a Form:

Imports System.Drawing

'This Grid object in defined at Form Class scope 
Public ColoredGrid As ColorGrid

'Button used to trigger the Grid painting
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    If ColoredGrid IsNot Nothing Then
        ColoredGrid.Dispose()
    End If
    ColoredGrid = New ColorGrid(Panel1)
    ColoredGrid.GridSize = New Size(300, 300)
    ColoredGrid.GridColumnsRows = New Size(10, 10)
    ColoredGrid.GridPosition = New Point(10, 10)
    ColoredGrid.GridColor = Color.White
    ColoredGrid.CellColor = Color.FromArgb(32, 32, 32)
    ColoredGrid.SelectedCellColor = Color.OrangeRed
    ColoredGrid.BuildGrid()
End Sub

This is a visual sample that shows how it works:

enter image description here

This is the main Grid class.
The ColorGrid Class supports IDisposable, because it registers the described events. These must be unregistered when the Class is not used anymore. Weird things can happen if you don't.

Public Class ColorGrid
    Implements IDisposable

    Private Grid As List(Of List(Of GridCell))
    Private CurrentGridSize As New Size(100, 100)
    Private GridColRows As New Size(10, 10)
    Private CellSize As New Size(10, 10)
    Private MouseCell As Point = Point.Empty
    Private Canvas As Control = Nothing
    Private UpdateCell As Boolean = False
    Private NewGrid As Boolean = False

    Public Sub New(DrawingControl As Control)
        If DrawingControl IsNot Nothing Then
            Me.Canvas = DrawingControl
            AddHandler Me.Canvas.Paint, New PaintEventHandler(AddressOf Me.ControlPaint)
            AddHandler Me.Canvas.MouseClick, New MouseEventHandler(AddressOf Me.MouseHandler)
            Me.GridPosition = New Point(10, 10)
            Me.CellColor = Color.FromArgb(32, 32, 32)
        End If
    End Sub

    Public Property GridPosition() As Point
    Public Property CellColor() As Color
    Public Property SelectedCellColor() As Color
    Public Property GridColor() As Color
    Public Property GridSize() As Size
        Get
            Return Me.CurrentGridSize
        End Get
        Set(value As Size)
            Me.CurrentGridSize = value
            SetCellSize()
        End Set
    End Property
    Public Property GridColumnsRows() As Size
        Get
            Return Me.GridColRows
        End Get
        Set(value As Size)
            Me.GridColRows = value
            SetCellSize()
        End Set
    End Property
    Private Property RefreshCell() As GridCell

    Friend Class GridCell
        Public Property Cell() As Rectangle
        Public Property CellColor() As Color
    End Class

    Private Sub SetCellSize()
        Me.CellSize = New Size((Me.CurrentGridSize.Width  Me.GridColRows.Width),
                               (Me.CurrentGridSize.Height  Me.GridColRows.Height))
        If Me.CellSize.Width < 4 Then Me.CellSize.Width = 4
        If Me.CellSize.Height < 4 Then Me.CellSize.Height = 4
    End Sub

    Public Sub BuildGrid()
        If Me.Canvas Is Nothing Then Return 

        Me.Grid = New List(Of List(Of GridCell))()
        For row As Integer = 0 To GridColumnsRows.Height - 1
            Dim RowCells As New List(Of GridCell)()
            For col As Integer = 0 To GridColumnsRows.Width - 1
                RowCells.Add(New GridCell() With {
                    .Cell = New Rectangle(New Point(Me.GridPosition.X + (col * Me.CellSize.Width),
                                                    Me.GridPosition.Y + (row * Me.CellSize.Height)),
                                          Me.CellSize),
                    .CellColor = Me.CellColor})
            Next
            Me.Grid.Add(RowCells)
        Next
        Me.NewGrid = True
        Me.Canvas.Invalidate()
    End Sub

    Private Sub ControlPaint(o As Object, e As PaintEventArgs)
        If Me.NewGrid Then
            e.Graphics.Clear(Me.Canvas.BackColor)
            Me.NewGrid = False
        End If

        Me.Grid.
            SelectMany(Function(rowcells) rowcells).
            Select(Function(colcell)
                       If Me.UpdateCell Then
                           Using brush As New SolidBrush(Me.RefreshCell.CellColor)
                               e.Graphics.FillRectangle(brush, Me.RefreshCell.Cell.X + 1, Me.RefreshCell.Cell.Y + 1,
                                                               Me.RefreshCell.Cell.Width - 1, Me.RefreshCell.Cell.Height - 1)
                           End Using
                           Me.UpdateCell = False
                           Return Nothing
                       Else
                           Using pen As New Pen(Me.GridColor)
                               e.Graphics.DrawRectangle(pen, colcell.Cell)
                           End Using
                           Using brush As New SolidBrush(colcell.CellColor)
                               e.Graphics.FillRectangle(brush, colcell.Cell.X + 1, colcell.Cell.Y + 1,
                                                               colcell.Cell.Width - 1, colcell.Cell.Height - 1)
                           End Using
                       End If
                       Return colcell
                   End Function).TakeWhile(Function(colcell) colcell IsNot Nothing).ToList()
    End Sub

    Private Sub MouseHandler(o As Object, e As MouseEventArgs)
        Me.RefreshCell = GetUpdateCell(e.Location)
        Me.RefreshCell.CellColor = Me.SelectedCellColor
        Dim CellColorArea As Rectangle = Me.RefreshCell.Cell
        CellColorArea.Inflate(-1, -1)
        Me.UpdateCell = True
        Me.Canvas.Invalidate(CellColorArea)
    End Sub

    Private Function GetUpdateCell(CellPosition As Point) As GridCell
        Return Me.Grid.
            SelectMany(Function(rowcells) rowcells).
            Select(Function(gridcell) gridcell).
            Where(Function(gridcell) gridcell.Cell.Contains(CellPosition)).
            First()
    End Function

    Public Sub Dispose() Implements IDisposable.Dispose
        If Me.Canvas IsNot Nothing Then
            RemoveHandler Me.Canvas.Paint, AddressOf Me.ControlPaint
            RemoveHandler Me.Canvas.MouseClick, AddressOf Me.MouseHandler
            Me.Grid = Nothing
        End If
    End Sub
End Class

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...