Search code examples
c#pictureboxpaintevent

Add CellPaint event to PictureBox with Grid painted on it


I created a Grid on the PictureBox like this:

private void PictureBoxPaint(object sender, PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            int numOfCellsWidth = 50;
            int numOfCellsHeight = 600;
            int cellSize = 20;
            Pen p = new Pen(Color.Black);

            for (int y = 0; y < numOfCellsHeight; ++y)
            {
                g.DrawLine(p, 0, y * cellSize, numOfCellsHeight * cellSize, y * cellSize);                    
            }

            for (int x = 0; x < numOfCellsWidth; ++x)
            {
                g.DrawLine(p, x * cellSize, 0, x * cellSize, numOfCellsHeight * cellSize);
            }
        }

And this is how it looks:
enter image description here

I worked with tableLayoutPanel before and it had a CellPaint event which I could bind to a list of arrays so that the color of cells would change when the list is changed. This is what I had:

private void tableLayoutPanelMainGrid_CellPaint(object sender, TableLayoutCellPaintEventArgs e)
{
    if (mainVisualization.mainGrid != null)
        if (mainVisualization.mainGrid.cellList != null)
            using (var b = new SolidBrush(mainVisualization.mainGrid.cellList[e.Column, e.Row].color))
                e.Graphics.FillRectangle(b, e.CellBounds);
}

How can I combine those two?


Solution

  • Unless your picturebox is huge I don't think it will be laggy. PBox is double-buffered and should work fine.

    Consider this: While your CellPaint event looks small it really is called for each cell each time, so the full surface of your TLP is being redrawn each time you invalidated it. So: Not much different to the situation with PBox..

    Here is an example of your own Paint and CellPaint. It uses a simple 2d-Color array and two ints to store the current cell size. Recalculate upon resizing the PictureBox board!

    Color[,] cellList;
    int cellWidth = 23;
    int cellHeight = 23;
    
    private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {
        if (cellList == null) InitCells(22, 22);
    
    
        for (int c = 0; c < cellList.GetLength(0); c++)
            for (int r = 0; r < cellList.GetLength(1); r++)
            {
                TableLayoutCellPaintEventArgs tep = new 
                    TableLayoutCellPaintEventArgs(e.Graphics,
                        Rectangle.Round(e.Graphics.ClipBounds),
                        new Rectangle(c*cellWidth, r*cellHeight, cellWidth, cellHeight), 
                        c, r);
                pictureBox1_CellPaint(e, tep);
            }
        // insert the gridline drawing here:
        for (int c = 0; c <= cellList.GetLength(1); c++)
                e.Graphics.DrawLine(Pens.DarkSlateBlue, 0, c * cellHeight, 
                                    cellWidth * cellList.GetLength(0), c * cellHeight);
        for (int c = 0; c <= cellList.GetLength(0); c++)
                e.Graphics.DrawLine(Pens.DarkSlateBlue, c * cellWidth, 0, 
                                    c * cellWidth, cellHeight * cellList.GetLength(1));
    }
    
    private void pictureBox1_CellPaint(object sender, TableLayoutCellPaintEventArgs e)
    {
        //if (mainVisualization.mainGrid != null)
        //    if (mainVisualization.mainGrid.cellList != null)
                using (var b = new SolidBrush(cellList[e.Column, e.Row]))
                    e.Graphics.FillRectangle(b, e.CellBounds);
    }
    

    You can see that it is a direct clone of the code you had for the TLP. Not sure if you really should do that, but it is an example how you can simulate the CellPaint event..

    Of course you will want to use your own cellList data structure..

    It is up to you to decide how you will integrate the drawing of the grid lines.The simplest way is to draw them after the cellPaint loop.

    By recalculating the cell size (and Invalidating the PictureBox) it will resize its content nicely:

    enter image description here