C# grotty graphics

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • rayreeves

    C# grotty graphics

    If I look for guidance on this topic I find simple examples like this:

    public class Form2:Form {
    public Form2() {
    this.Text = "FORM2";
    this.Size = new Size(450,400);
    this.Paint += new PaintEventHandl er(Draw_Graphic s);
    }

    public void Draw_Graphics(o bject sender,PaintEve ntArgs e)
    {
    Graphics g = e.Graphics;
    System.Drawing. Bitmap bmap = new System.Drawing. Bitmap(500, 400);
    for(int i = 0; i < 500; i++)
    for(int j = 0; j < 50; j++)
    bmap.SetPixel(i , j, Color.Red);
    g.DrawImage(bma p,200,100);
    }
    };

    static void Main()
    {
    Application.Run (new Form2());
    }

    This works as advertised but there is some sly sleight of hand going on
    here.
    Apparently the Form2 constructor raises a signal that is caught by the
    handler Draw_Graphics() .
    What was the signal and who raised it?
    I ask because if I replace the innocuous-looking statement
    "Application.Ru n" by a simple call to the constructor it executes that but
    no event is raised and the handler does not run.
    What is the dark secret here? What does Application.Run () actually do?

    Now I want to run a dialog box first and then perform the above, so I say:

    Application.Run (new Form1())
    Application.Exi t();
    Application.Run (new Form2())

    No dice! I get Form1 and the Form2 constructor but no signal.

    Ray Reeves




  • Jon Skeet [C# MVP]

    #2
    Re: C# grotty graphics

    <"rayreeves" <ray<mond>reeve s@verizon.net>w rote:
    If I look for guidance on this topic I find simple examples like this:
    >
    public class Form2:Form {
    public Form2() {
    this.Text = "FORM2";
    this.Size = new Size(450,400);
    this.Paint += new PaintEventHandl er(Draw_Graphic s);
    }
    >
    public void Draw_Graphics(o bject sender,PaintEve ntArgs e)
    {
    Graphics g = e.Graphics;
    System.Drawing. Bitmap bmap = new System.Drawing. Bitmap(500, 400);
    for(int i = 0; i < 500; i++)
    for(int j = 0; j < 50; j++)
    bmap.SetPixel(i , j, Color.Red);
    g.DrawImage(bma p,200,100);
    }
    };
    >
    static void Main()
    {
    Application.Run (new Form2());
    }
    >
    This works as advertised but there is some sly sleight of hand going on
    here.
    Apparently the Form2 constructor raises a signal that is caught by the
    handler Draw_Graphics() .
    No, the Windows message loop requests that the form is painted, and the
    constructor to Form2 registers a handler for the paint event.
    What was the signal and who raised it?
    I ask because if I replace the innocuous-looking statement
    "Application.Ru n" by a simple call to the constructor it executes that but
    no event is raised and the handler does not run.
    What is the dark secret here? What does Application.Run () actually do?
    It starts a Windows message loop.
    Now I want to run a dialog box first and then perform the above, so I say:
    >
    Application.Run (new Form1())
    Application.Exi t();
    Application.Run (new Form2())
    >
    No dice! I get Form1 and the Form2 constructor but no signal.
    Well, you don't want Application.Exi t() in there - that will exit the
    application (as the name suggests) unless you have any other threads
    running.

    --
    Jon Skeet - <skeet@pobox.co m>
    http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
    If replying to the group, please do not mail me too

    Comment

    • Barry Kelly

      #3
      Re: C# grotty graphics

      "rayreeves" <ray<mond>reeve s@verizon.netwr ote:
      If I look for guidance on this topic I find simple examples like this:
      >
      public class Form2:Form {
      public Form2() {
      this.Text = "FORM2";
      this.Size = new Size(450,400);
      this.Paint += new PaintEventHandl er(Draw_Graphic s);
      }
      >
      public void Draw_Graphics(o bject sender,PaintEve ntArgs e)
      {
      Graphics g = e.Graphics;
      System.Drawing. Bitmap bmap = new System.Drawing. Bitmap(500, 400);
      for(int i = 0; i < 500; i++)
      for(int j = 0; j < 50; j++)
      bmap.SetPixel(i , j, Color.Red);
      g.DrawImage(bma p,200,100);
      }
      };
      >
      static void Main()
      {
      Application.Run (new Form2());
      }
      >
      This works as advertised but there is some sly sleight of hand going on
      here.
      Yes. It's Win32's windowing system.
      Apparently the Form2 constructor raises a signal that is caught by the
      handler Draw_Graphics() .
      No. Application.Run () contains a loop (called the "message loop" or
      "message pump") which does basically two things in its body:

      1) Retrieve a message from Windows (see e.g. GetMessage and PeekMessage
      in MSDN docs)
      2) Dispatch that message from Windows (see e.g. DispatchMessage in MSDN
      docs)

      Messages are things like WM_PAINT, which is a request to paint a window
      (for example, the window might have been obscured by another window, and
      is now visible). Messages contain several parameters: the message code
      (WM_PAINT in this case), the window it applies to, and two parameters
      whose meaning changes based on message kind (wParam and lParam).

      Retrieving the message and dispatching the message are done by the
      application so that it happens on a thread the application controls.

      Dispatching the message sends it off to something called a window
      procedure, which is a function pointer (a bit like a delegate)
      associated with that window in the OS. When the window is first created,
      the creator of the window gets a chance to specify this window procedure
      (see CreateWindow in MSDN docs).

      The window procedure for .NET controls is Control.WndProc . Basically,
      different descendants of Control have 'case' statements that switch on
      the message type and call different methods based on the message.

      In Control.WndProc , there's an entry in this 'case' statement that calls
      a private method called WmPaint, which in turn calls
      PaintWithErrorH andling, which itself calls OnPaint, which finally calls
      the 'Paint' event if it is non-null.

      I'm leaving out many details, but that's the gist of it.
      Now I want to run a dialog box first and then perform the above, so I say:
      >
      Application.Run (new Form1())
      This sets up a message loop and keeps going until the application exits
      (with Application.Exi t) or the main form (the argument) is closed.
      Application.Exi t();
      Because there's no loop to exit, this does nothing. The documentation
      for this method says:

      "Informs all message pumps that they must terminate, and then closes all
      application windows after the messages have been processed."

      Because there's no message pump active (Application.Ru n() is not
      running), and there's no forms on screen at this point, the method won't
      do anything.
      Application.Run (new Form2())
      This shows a second form, in a new loop.

      -- Barry

      --

      Comment

      • Jon Skeet [C# MVP]

        #4
        Re: C# grotty graphics

        Jon Skeet [C# MVP] <skeet@pobox.co mwrote:
        Well, you don't want Application.Exi t() in there - that will exit the
        application (as the name suggests) unless you have any other threads
        running.
        Doh! Ignore this bit, and read Barry's answer instead, which is much
        more sensible.

        --
        Jon Skeet - <skeet@pobox.co m>
        http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
        If replying to the group, please do not mail me too

        Comment

        • rayreeves

          #5
          Re: C# grotty graphics


          "Barry Kelly" <barry.j.kelly@ gmail.comwrote in message
          news:e8cju2d09v aqh1bqnnfq03q24 84aq2oa7j@4ax.c om...
          "
          >Application.Ru n(new Form2())
          >
          This shows a second form, in a new loop.
          >
          -- Barry
          >
          --
          http://barrkel.blogspot.com/
          Thanks for the comprehensive and detailed response.
          Unfortunately, the second form Form2 does not appear, unless it is the only
          form. It would be nice to know if a Paint event actually occurred and who
          caught it.

          I don't even really want to paint on a Form but it's not apparent to me that
          I can just create a window. I would also like to SetPixel directly in the
          window without using BitMaps so that I can watch the picture grow, but that
          doesn't seem possible either.

          Ray Reeves


          Comment

          • Barry Kelly

            #6
            Re: C# grotty graphics

            "rayreeves" <ray<mond>reeve s@verizon.netwr ote:
            Thanks for the comprehensive and detailed response.
            Unfortunately, the second form Form2 does not appear, unless it is the only
            form. It would be nice to know if a Paint event actually occurred and who
            caught it.
            The second form should appear after you close the first. It does in this
            simple test program:

            ---8<---
            using System;
            using System.Windows. Forms;

            class App
            {
            public static void Main()
            {
            Application.Run (new Form());
            Application.Exi t();
            Application.Run (new Form());
            }
            }
            --->8---
            I don't even really want to paint on a Form but it's not apparent to me that
            I can just create a window. I would also like to SetPixel directly in the
            window without using BitMaps so that I can watch the picture grow, but that
            doesn't seem possible either.
            Windows doesn't use a "retained mode" graphics infrastructure.
            Everything is lost if the window is obscured in any way. You need to
            draw to a bitmap, and keep the bitmap around. For example:

            ---8<---
            using System;
            using System.Drawing;
            using System.Windows. Forms;

            class MyForm : Form
            {
            Bitmap _image = new Bitmap(500, 500);
            Button _testButton = new Button();
            Random r = new Random();

            public MyForm()
            {
            Paint += MyPaintEvent;
            using (Graphics g = Graphics.FromIm age(_image))
            g.FillRectangle (Brushes.White, 0, 0, 500, 500);
            ClientSize = new Size(500, 500);
            _testButton.Par ent = this;
            _testButton.Tex t = "Click Here";
            _testButton.Cli ck += MyClickEvent;
            DoubleBuffered = true;
            }

            void MyClickEvent(ob ject sender, EventArgs e)
            {
            // Random color for RGB fields, and 'OR' in 255 for Alpha.
            Color c = Color.FromArgb( r.Next(0x100000 0) | (0xFF << 24));
            using (Graphics g = Graphics.FromIm age(_image))
            {
            using (Pen p = new Pen(c))
            g.DrawLine(p, r.Next(500), r.Next(500),
            r.Next(500), r.Next(500));
            }
            _image.SetPixel (r.Next(500), r.Next(500), c);
            // Invalidate() needed to get windows to send paint message
            // to repaint form.
            Invalidate();
            }

            void MyPaintEvent(ob ject sender, PaintEventArgs e)
            {
            e.Graphics.Draw Image(_image, 0, 0);
            }

            public static void Main()
            {
            Application.Run (new MyForm());
            }
            }
            --->8---

            -- Barry

            --

            Comment

            • rayreeves

              #7
              Re: C# grotty graphics

              I do exactly that in my code but don't succeed. Somehow my Dialog Form is
              intercepting the Paint event, if there is one. Its true that a simpler Form1
              does work properly for me..I'll have to try whitteling down my Dialog bit by
              bit.
              I am very much obliged for your kind attention and detailed help.

              Ray Reeves

              "Barry Kelly" <barry.j.kelly@ gmail.comwrote in message
              news:ea3mu2pj48 elpqg1rtm46dmhe 5nv7r2iq3@4ax.c om...
              "rayreeves" <ray<mond>reeve s@verizon.netwr ote:
              >
              >Thanks for the comprehensive and detailed response.
              >Unfortunatel y, the second form Form2 does not appear, unless it is the
              >only
              >form. It would be nice to know if a Paint event actually occurred and who
              >caught it.
              >
              The second form should appear after you close the first. It does in this
              simple test program:
              >
              ---8<---
              using System;
              using System.Windows. Forms;
              >
              class App
              {
              public static void Main()
              {
              Application.Run (new Form());
              Application.Exi t();
              Application.Run (new Form());
              }
              }
              --->8---
              >
              >I don't even really want to paint on a Form but it's not apparent to me
              >that
              >I can just create a window. I would also like to SetPixel directly in the
              >window without using BitMaps so that I can watch the picture grow, but
              >that
              >doesn't seem possible either.
              >
              Windows doesn't use a "retained mode" graphics infrastructure.
              Everything is lost if the window is obscured in any way. You need to
              draw to a bitmap, and keep the bitmap around. For example:
              >
              ---8<---
              using System;
              using System.Drawing;
              using System.Windows. Forms;
              >
              class MyForm : Form
              {
              Bitmap _image = new Bitmap(500, 500);
              Button _testButton = new Button();
              Random r = new Random();
              >
              public MyForm()
              {
              Paint += MyPaintEvent;
              using (Graphics g = Graphics.FromIm age(_image))
              g.FillRectangle (Brushes.White, 0, 0, 500, 500);
              ClientSize = new Size(500, 500);
              _testButton.Par ent = this;
              _testButton.Tex t = "Click Here";
              _testButton.Cli ck += MyClickEvent;
              DoubleBuffered = true;
              }
              >
              void MyClickEvent(ob ject sender, EventArgs e)
              {
              // Random color for RGB fields, and 'OR' in 255 for Alpha.
              Color c = Color.FromArgb( r.Next(0x100000 0) | (0xFF << 24));
              using (Graphics g = Graphics.FromIm age(_image))
              {
              using (Pen p = new Pen(c))
              g.DrawLine(p, r.Next(500), r.Next(500),
              r.Next(500), r.Next(500));
              }
              _image.SetPixel (r.Next(500), r.Next(500), c);
              // Invalidate() needed to get windows to send paint message
              // to repaint form.
              Invalidate();
              }
              >
              void MyPaintEvent(ob ject sender, PaintEventArgs e)
              {
              e.Graphics.Draw Image(_image, 0, 0);
              }
              >
              public static void Main()
              {
              Application.Run (new MyForm());
              }
              }
              --->8---
              >
              -- Barry
              >
              --
              http://barrkel.blogspot.com/

              Comment

              • rayreeves

                #8
                Re: C# grotty graphics

                What I have found is that if the Form1 Dialog Box contains plain buttons
                then when they are pressed, even if they do nothing, the Paint signal to
                Form2 is pre-empted! Closing the Form1 window is the only way to get to
                Form2.
                Grotty!

                Ray Reeves


                Comment

                Working...