Search code examples
c#.netwinformsdrawing

Problem with refreshing canvas in windows form application


I'm trying to make sorting visualization algorithm in c# but I got a problem with the canvas refreshing.

I tried to refresh the canvas every time I redraw but its not looks good. I'm sure there is another way to do it and I hope someone can help me.

In this picture you can see the black rectangles that I want to delete from the canvas

pic

This is my code :

    private void GenerateArrayButton_Click(object sender, EventArgs e)
    {
        MyCanvas.Refresh();
        Random random = new Random();
        int xPosition = 0 , yPosition = MyCanvas.Height/2; 
        const int k_RectangleWight = 2;

        for(int i = 0; i < k_SizeOfArray; i++)
        {
            int rectangleHeight = random.Next(MyCanvas.Height / 2);
            m_UnsortedArray[i] = new Rectangle(xPosition,yPosition, k_RectangleWight, rectangleHeight);
            xPosition += 5;
        }

        draw(m_UnsortedArray, Pens.Black);

    }

    private void draw(Rectangle[] i_ArrayToDraw, Pen i_PenColor)
    {
        var graphics = MyCanvas.CreateGraphics();
        graphics.DrawRectangles(i_PenColor, i_ArrayToDraw);
        graphics.Dispose();
    }

    private void SortingButton_Click(object sender, EventArgs e)
    {
        bubbleSort();
        draw(m_UnsortedArray, Pens.Green);
    }

    private void bubbleSort()
    {
        for(int i = 0; i < m_UnsortedArray.Length; i++)
        {
            for(int j = 0; j < m_UnsortedArray.Length - 1; j++)
            {
                if(m_UnsortedArray[j].Height > m_UnsortedArray[j + 1].Height)
                {
                    swap(ref m_UnsortedArray[j], ref m_UnsortedArray[j+1]);
                }
            }
            draw(m_UnsortedArray,Pens.Black);
        }
    }

    private void swap(ref Rectangle i_Rectangle1, ref Rectangle i_Rectangle2)
    {
        // Swap the position of the rectangle
        var location = i_Rectangle1.Location;
        i_Rectangle1.Location = i_Rectangle2.Location;
        i_Rectangle2.Location = location;

        // Swap the position of the current rectangle in the array
        var copyRect = i_Rectangle1;
        i_Rectangle1 = i_Rectangle2;
        i_Rectangle2 = copyRect;
    }

}

Solution

  • The drawing canvas in question MyCanvas whether its a PictureBox or a Panel or the Form itself, provides specific events for the painting routines, particularly the Paint event in this context. The event has a PaintEventArgs which provides a free Graphics object to do your drawings. Meaning, you don't need to create extra Graphics objects like in your draw method. Now let's draw those rectangles.

    Class level fields:

    using System.Threading.Tasks;
    //...
    
    public partial class Form1 : Form
    {
        private const int k_RectangleWight = 2;
        private const int k_SizeOfArray = 100; //assign the right value.
    
        private Rectangle[] m_UnsortedArray;
        Random rand = new Random();
        private Pen MyPen;
    

    Handle the Paint event of the MyCanvas control.

        public Form1()
        {
            InitializeComponent();
    
            //You can add normal event handler instead if you prefer so.
            MyCanvas.Paint += (s, e) =>
            {
                if (MyPen != null)
                    e.Graphics.DrawRectangles(MyPen, m_UnsortedArray);
            };
        }
    

    In the GenerateArrayButton_Click event, create the rectangles, assign the drawing pen, and call the Invalidate() method of the drawing canvas.

        private void GenerateArrayButton_Click(object sender, EventArgs e)
        {
            m_UnsortedArray = new Rectangle[k_SizeOfArray];
            var xPosition = 0;
            var yPosition = MyCanvas.Height / 2;
            for(var i = 0; i < k_SizeOfArray; i++)
            {
                var rectangleHeight = rand.Next(MyCanvas.Height / 2);
                m_UnsortedArray[i] = new Rectangle(
                    xPosition, 
                    yPosition, 
                    k_RectangleWight, 
                    rectangleHeight);
                xPosition += 5;
            }
            MyPen = Pens.Black;
            MyCanvas.Invalidate();
        }
    

    At this point, you will get something drawn like this:

    SOQ61443730A

    Now the second part. Your methods for swapping the rectangles:

        private async void bubbleSort()
        {
            for (int i = 0; i < m_UnsortedArray.Length; i++)
            {
                for (int j = 0; j < m_UnsortedArray.Length - 1; j++)
                    if (m_UnsortedArray[j].Height > m_UnsortedArray[j + 1].Height)
                        swap(ref m_UnsortedArray[j], ref m_UnsortedArray[j + 1]);
                await Task.Delay(30);
                MyCanvas.Invalidate();
            }
        }
    
        private void swap(ref Rectangle i_Rectangle1, ref Rectangle i_Rectangle2)
        {
            var location = i_Rectangle1.Location;
            i_Rectangle1.Location = i_Rectangle2.Location;
            i_Rectangle2.Location = location;
    
            var copyRect = i_Rectangle1;
            i_Rectangle1 = i_Rectangle2;
            i_Rectangle2 = copyRect;
        }
    

    In the click event of the SortingButton, you just need to:

        private void SortingButton_Click(object sender, EventArgs e)
        {
            MyPen = Pens.Green;
            bubbleSort();
        }
    }
    

    ... and you will get:

    SOQ61443730C