Search code examples
c#winformsimagerepaint

Label text doesn't get updated until the whole loop is completed


I have a Winform program that does some calculations when the user clicks on a button and then calls the picturebox paint event to draw a new BMP based on the results of the calculations. This works fine.

Now I want to do this 100 times and every time the picturebox is refreshed, I want to see the iteration that it's currently in by updating the text on a label as per below:

 private void button2_Click(object sender, EventArgs e)
        {

        for (int iterations = 1; iterations <= 100; iterations++)
        {
            // do some calculations to change the cellmap parameters
            cellMap.Calculate();

            // Refresh picturebox1
            pictureBox1.Invalidate();
            pictureBox1.Update();

            // Update label with the current iteration number
            label1.Text = iterations.ToString();
        }
    }

    private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {

        Bitmap bmp = new Bitmap(cellMap.Dimensions.Width, cellMap.Dimensions.Height);
        Graphics gBmp = Graphics.FromImage(bmp);

        int rectWidth = scaleFactor;
        int rectHeight = scaleFactor;

         // Create solid brushes
        Brush blueBrush = new SolidBrush(Color.Blue);
        Brush greenBrush = new SolidBrush(Color.Green);
        Brush transparentBrush = new SolidBrush(Color.Transparent);

        Graphics g = e.Graphics;

        for (int i = 0; i < cellMap.Dimensions.Width; i++)
        {
                for (int j = 0; j < cellMap.Dimensions.Height; j++)
                {
                    // retrieve the rectangle and draw it
                    Brush whichBrush;

                    if (cellMap.GetCell(i, j).CurrentState == CellState.State1)
                    {
                        whichBrush = blueBrush;
                    }
                    else if (cellMap.GetCell(i, j).CurrentState == CellState.State2)
                    {
                        whichBrush = greenBrush;
                    }
                    else
                    {
                        whichBrush = transparentBrush;
                    }

                    // draw rectangle to bmp
                    gBmp.FillRectangle(whichBrush, i, j, 1f, 1f);
                }
         }

         g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
         g.DrawImage(bmp, 0, 0, pictureBox1.Width, pictureBox1.Height);
    }

The problem I am having is that the label text only gets displayed after the last picturebox update is completed. So essentially, it does not display 1 through to 99. I can see the picturebox updates after every refresh as the BMP changes with every iteration. Any idea?


Solution

  • To answer your question about why you have to do it: Windows Forms Programs run everything in a single thread - the UI thread. This means it must execute code in order, so that it will finish a function before it can switch back to the UI code. In other words, it can't update the pictures until after its finished with the function, so if you updated the picture 100 times, only the last one will actually get updated. Using the Invalidate/Update code tells the compiler to "pause" execution of the function and forces it to update the UI instead of waiting till the end of the function. Hope that helps!