0

I have a loop in a loop to affect a lot of variables, after which I need to display the data in text form via SendKeys.Send and take a screenshot. But when the program starts, the loop produces screenshots, but in the text version it is displayed only at the last moment when all the screenshots have already been taken

private void button1_Click(object sender, EventArgs e)
    {

        int ID = Convert.ToInt32(textBox1.Text); //Тип одежды
        int drawable = Convert.ToInt32(textBox2.Text); //Кол-во одежды
        int Z = Convert.ToInt32(textBox3.Text); //Кол-во цветов
        int all = 1;
        
        Thread.Sleep(2000);
        for(int i = 0; i < drawable + 1; i++)
        {
            
            int m1 = 0;
            for (int m=m1; m< Z + 1;m++)
            {
                SendKeys.Send("t");
                SendKeys.Send("/setclothes " + ID + " " + i + " " + m);
                m1 = m;                    
                
                    int l = 32;
                    string filename = String.Format("D:\\Test\\" + ID + "_" + i + "_" + m + ".png", l);
                    Bitmap printscreen = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
                    Graphics graphics = Graphics.FromImage(printscreen as Image);
                    graphics.CopyFromScreen(0, 0, 0, 0, printscreen.Size);
                    printscreen.Save(filename, System.Drawing.Imaging.ImageFormat.Png);
                
            }
            
        }
LarsTech
  • 80,625
  • 14
  • 153
  • 225
  • 1
    You should be painting in an `OnPaint` handler, not in a `Click` handler. WinForms GDI is not a _retained-mode_ graphics library. – Dai Sep 16 '21 at 03:11

1 Answers1

2

Your thread does not allow the graphics (on another thread) to refresh. So that when the graphics.CopyFromScreen is called the changes are complete but QUEUED and so no actual changes have occured until the main thread has completed (your function ends).

Try using:

Application.DoEvents();

before the graphics.CopyFromScreen line to force the graphics to update before the screen shot is taken.

i.e.

Bitmap printscreen = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
Graphics graphics = Graphics.FromImage(printscreen as Image);
Application.DoEvents();
graphics.CopyFromScreen(0, 0, 0, 0, printscreen.Size);
printscreen.Save(filename, System.Drawing.Imaging.ImageFormat.Png);

note: Calling DoEvents will stop work on the current thread and do work on other threads. This could slow down your loop significantly if you are running lots of other applications in the background!

note2: I would create the bitmap outside the loop unless you expect the screen resolution to change. Allocating room for the bitmap hundreds of times is slow.

Jon P
  • 117
  • 4
  • 2
    BTW, you should be using `using()` blocks on those GDI objects. Also, rather than suggesting using `DoEvents()` I'd just run the graphics operations in a background thread with `await`. – Dai Sep 16 '21 at 04:55
  • @Dai Both good suggestions! using blocks are definitely mandatory here! DoEvents is a fast solution for people who don't want to or don't know how to use asynchronous events in code. – Jon P Sep 17 '21 at 23:03