0
votes

I found that there is difference between Graphics g and e.Graphics from paint event .. e.Graphics is something like "more PRO" which allows more fun with transformations matrices.
Transformations like this https://msdn.microsoft.com/en-us/library/eews39w7(v=vs.110).aspx

I'm writing app, where will be several objects. In this question there is example C# rotation (transformation) issue

I found how OnPaint method could be overrided here https://msdn.microsoft.com/en-us/library/b818z6z6(v=vs.71).aspx


The think I don't understand is usecase how I should use it. I need override OnPaint method - ok, but on what object??

Lets imagine simple situation I will have Form in c#

 public partial class Form1 : Form {

 private Bitmap canvasBitmap; //bitmap for drawing
 private Graphics g;          
 ...

public Form1() {
       //on Form there is placed PictureBox called canvas
       //so canvas is PictureBox 640x480 px
       canvasBitmap = new Bitmap(canvas.Width, canvas.Height);
       canvas.Image = canvasBitmap;

       //prepare graphics
       g = Graphics.FromImage(canvasBitmap);
       g.SmoothingMode = SmoothingMode.AntiAlias;
       ...
      g.Invalidate();     
}
}

All drawing will be done on PictureBox which will be my canvas. Is ok to keep there the Graphics g and not the e.Graphics?

Than I will have some objects:

List<Fish> fishes = new List<Fish>();
List<Food> food = new List<Food>(); 

And I will want to do some fun stuff with them e.g. some transformations like here (scalling, translation, rotation) https://msdn.microsoft.com/en-us/library/eews39w7(v=vs.110).aspx

Here are the objects. I tryed to write that OnPaint method (not sure if its on correct place.)

 class Fish {
     Point position;

      Fish(int x, int y) {
        ...
      }

    protected override void OnPaint(PaintEventArgs e){
     ...
    }
 }


    class Food {

      Point position;

      public Food(int x, int y) {

       ...
     }

     protected override void OnPaint(PaintEventArgs pe) {

       ....
     }

}

The question is: How should be used in this case OnPaint method? What is the usecase of using this? I guess I will probably override this method on Fish and Food object like I did it. How I draw it? How I redraw it? How I put it on my Graphics g canvas in Form? Where and how should be used Invalidate?
normaly i use

canvas.Invalidate();

see the form example. Can I mix Graphics g and e.Graphics? There could be also with e.Graphics used some doublebuffering or something like that.

Edit
E1) So Form and PicutreBox are control? My Fish and Food class are not controll? Ok?
E2) On Picture box can be somehow up to 3 graphics I can switch and its for smooth drawing. But for simplicity I can stay with one? Ok?
E3) Graphics g is tool e.Graphics is some wrapper of some graphics library which have in it some support for transformatins (work with transformation matrices). OK?
E4) OnPaint(PaintEventArgs e) will make me able use e.Graphics, but if I have my "loop" in timer (in handle of timer object which I simply put on my form and set the period) and from it I call the method for update and update all objects of fishes and food in some lists(Update = do transformations with them according to my calculation). Is possible somehow use the methods of e.Graphics here?
E5) If E1 is true, the override OnPaint methods in Food and Fish class is nonsense ok?

1
Using Graphics.FromImage() is okayish here, you are drawing to the bitmap, not the screen. It is PictureBox.OnPaint() that paints. You do have to help and call the PictureBox.Invalidate() method to let it know that you've modified the bitmap and therefore needs to be repainted. Biggest issue is with the image size, canvas.Width/Height is the design size, it will not be the actual size on any modern machine. Or for that matter when the user resizes the window. Use the PictureBox.Resize event to know that the image needs to be adjusted.Hans Passant
Well the Form is Control, PictureBox is Controll, my Fish class or Food class is not controll? My motivation at this moment is simplicity and working stuff. I only need to work with abou 60 objects, count their behaviour with neural net and simply show them. If i will use OnePaint method I can get e.Graphics but how can I use that e.Graphics for example in timer (timer handle method which is on my form)? The Graphisc g methods are easy to call but I didn't get how to use e.Graphics methods explicitly. Only advantage of e.Graphics for me that it has more methods for transformations.user1097772
E1: Ys and no. E2: PBox can have Image, BackgoundImage and its surface. Yes you can stay with just one. E3: Graphics is all the same class, no matter where you get it from. No. In the timer.Tick you only triggerr the paint by callling Invalidate on the control. The paint then need to have access to the data, best by storing the data (coordinates etc) in one or more or a list of class level varaibles. E5: Indeed, there is no base (beyond object) and therefore nothing to override.TaW

1 Answers

1
votes

e.Graphics is coming from the OnPaint or Paint event and therefore only for controls.

The Graphics object you create from a bitmap is just for that bitmap.

You should use the one you actually want: Draw on the surface or into a bitmap.

Note that the bitmap may or may not be displayed (below the surface) in a controls.

A picturebox for example can even display two bitmaps below its surface, so you may want to use three Graphics objects for it..

They do the same things to different pixels and no, you can't do more with one..! You can apply matrix and other transformation with either.

The reason behing having the e.Graphics from the OnPaint parameters is that the system needs to do some repainting all its controls in a form at some times and therefore must call your drawing code in addition to the internal control drawing routines.

So you need to use this event and/or its e.Graphics or else your drawing will disappear upon such redrawing. Using e.Graphics for drawing onto controls will make the drawing persist. (*)

The bitmaps on the other hand will always be shown in their current state. No need to redraw them; just call Refresh() once after finishing your changes to let the System know about them.

Finally: DoubleBuffering is a property for controls, not the Graphics object. Note that is is hidden for most, especailly containers like Panel, so to turn it on you need to subclass them. PictureBox is meant for drawing and has DoubleBuffered = true out of the box.

The Graphics object does not contain any graphics; it is a tool that lets you draw onto a related bitmap, including a control's surface.

(*) Note that not all drawing needs or is supposed to persist: A rubberband line or rectangle should not and here you use the 3rd Graphics construstor: Graphics g = someControl.CreateGraphics();.