Thread: graphic updates not doing what i thought

  1. #1
    Registered User
    Join Date
    Oct 2008
    Posts
    85

    graphic updates not doing what i thought

    please bear with me on this question, i am still not sure if this is where my problem is but i need to clarify a few points.

    i am rendering a grid to a split control panel ( panel2)

    i have already overridden the onpaint call and in it i create a new graphic reference to the panel

    Code:
    protected override void OnPaint(PaintEventArgs e)
            {
    
                //base.OnPaint(e);
                     Graphics graphics = splitContainer1.Panel2.CreateGraphics();
                
                    graphics.Clear(Color.DimGray);
                    graphics.DrawImage(backg, 0, 0); 
                                                 // backg is a bitmap of same dimensions as panel 2
                
            }

    i have also tried to use override this way

    Code:
    protected override void OnPaint(PaintEventArgs e)
            {
    
                //base.OnPaint(e);
    
                       // i assumed 'e' would hold the area i invalidated  
     
                    e.Graphics.Clear(Color.DimGray);
                    e.Graphics.DrawImage(backg, 0, 0);
                
    
            }
    but this does not render the panel at all.( see comment in snippet)

    so first question - does the Onpaint event redraw everything on the screen or just the area you have invalidated ?( in this case panel2) and can i tell by looking at the PaintEventArgs ?

    i am also trying to eliminate some slight flicker when i click the panel and also if i drag a rectangle around on the panel it is very slow and jerky, which gives very noticable flickering. ( hand coded routine for drag method)

    i am using :-
    panel 2 mousedown ( to set start position of rectangle)
    panel 2 mousemove ( to update the end position, set a dragging flag, and redraw the grid & rectangle(calls update method))
    panel 2 mouseup ( to confirm the final position and redraw the grid + fill whatever area the rectangle encompassed)

    the update routine redraws everything on the "backg" bitmap for rendering.

    it draws the initial grid
    it draws an array over the grid and populates it

    and finally (if the dragging flag is set) it draws the outline of the rectangle over the grid and whatever is in it and calls this.Invalidate(); to force a redraw.

    so second question - are these mouse events the correct places to do the jobs i am doing and if not where should they be placed ?

    i realise this is probably very awkward to deal with without the full code but it is currently all on one form and runs to about 900 lines so i didint want to post it all.
    (yes i know it should be in classes - but that is for another day)

    EDIT:
    i have cleared the rectangle redraw problem by adding a this.update(); immediately after this.Invalidate();

    but still have terrible flickering
    Last edited by deviousdexter; 11-28-2008 at 10:57 AM.

  2. #2
    Registered User
    Join Date
    Aug 2008
    Posts
    188
    i'd recommend against the 1st method. it looks like it might work, but it's horribly inefficient. call CreateGraphics() once. as the method implies, it creates a graphics object, which is disposable....you don't want to leak a Graphics object every time the control refreshes...do you!??!?

    and the only reason why it wouldn't draw is if backg doesn't have stuff in it. have you tried commenting that out and try Clear()ing differently colors?

    1) the Paint event only invalidates the size of the control, not the entire screen.

    if you want to eliminate flickering, you need to enable DoubleBuffered on the Form, or make your own buffer, which involves drawing to a local Bitmap, then in the Paint event you draw the entire image onto the Graphics (rather than drawing on Graphics directly).

    2) your mouse events sound like they'd work.
    Last edited by bling; 11-28-2008 at 11:04 AM.

  3. #3
    Registered User
    Join Date
    Oct 2008
    Posts
    85
    thanks bling - now you mention it i havent enabled double buffering so i will go and set that up now and see if it helps my flickering issue.

    EDIT:

    added this into form1

    Code:
               this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
                this.SetStyle(ControlStyles.UserPaint, true);
                this.SetStyle(ControlStyles.DoubleBuffer, true);
                this.UpdateStyles();
    but now my panel2 loads as blank when i debug the app. when i move over a few textboxs i use for debugging values it draws again but now my rectangle doesnt appear when i clck and drag
    Last edited by deviousdexter; 11-28-2008 at 11:12 AM.

  4. #4
    Registered User
    Join Date
    Aug 2008
    Posts
    188
    another thing i noticed...if panel2 is what you want the changes to reflect, you're overriding the wrong method.

    your override OnPaint looks like you're overriding the Form, not the panel2's paint. try hooking into the splitContainer.Panel2.Paint event.

  5. #5
    Registered User
    Join Date
    Oct 2008
    Posts
    85
    i have added an override for the panel2 paint method :-

    Code:
     public void splitContainer1_Panel2_Paint(object sender, PaintEventArgs e)
            {
    
            }
    
            public override void  splitContainer1_Panel2_Paint(object sender, PaintEventArgs e)
            {
            
            }
    but i get the IDE error

    Error 1 'ImagelistTest.Form1.splitContainer1_Panel2_Paint( object, System.Windows.Forms.PaintEventArgs)': no suitable method found to override C:\Users\dexter\Documents\Visual Studio 2008\Projects\ImagelistTest\ImagelistTest\Form1.cs 898 31 ImagelistTest
    Error 2 The call is ambiguous between the following methods or properties: 'ImagelistTest.Form1.splitContainer1_Panel2_Paint( object, System.Windows.Forms.PaintEventArgs)' and 'ImagelistTest.Form1.splitContainer1_Panel2_Paint( object, System.Windows.Forms.PaintEventArgs)' C:\Users\dexter\Documents\Visual Studio 2008\Projects\ImagelistTest\ImagelistTest\Form1.De signer.cs 82 50 ImagelistTest

    if i comment out the original paint handler i get another error

    Error 1 'ImagelistTest.Form1.splitContainer1_Panel2_Paint( object, System.Windows.Forms.PaintEventArgs)': no suitable method found to override C:\Users\dexter\Documents\Visual Studio 2008\Projects\ImagelistTest\ImagelistTest\Form1.cs 898 31 ImagelistTest

    i have had them set to protected and public and get the same errors
    Last edited by deviousdexter; 11-28-2008 at 11:48 AM.

  6. #6
    Registered User
    Join Date
    Aug 2008
    Posts
    188
    hmmm, hope this explains it.
    Code:
    class MyForm {
      public MyForm() {
        this.Paint += PaintHandler;
      }
    
      protected override OnPaint(PaintEventArgs e) {
        // this 'overrides' the base class (Form) painting method.
        base.OnPaint(e);
        e.Graphics.Draw(1); // for simplicity, let's assume this is valid and outputs 1
      }
    
      private void PaintHandler(object sender, PaintEventArgs e) {
        // this listens to the paint
        e.Graphics.Draw(2); // outputs 2
      }
    };
    
    when the above class refreshes it will draw 1 and then 2.
    there are 2 ways to draw on a control. the 1st is to override the Paint method (of which you should *not* comment out the base.OnPaint()). and the 2nd is to listen to the event, which you need to do if you are not a subclass.

  7. #7
    Registered User
    Join Date
    Oct 2008
    Posts
    85
    ok - im getting more confused

    if i add a paint handler to the panel2 properties it creates this

    Code:
    protected void splitContainer1_Panel2_Paint(object sender, PaintEventArgs e)
            {
    
            }
    a. why cant i use the override to change it to my event handler( as i can do with OnPaint)

    b. can i just put what i want it to paint in there - as in my 'backg' bitmap ?

    i get what your saying about the creategraphics being recreated on every paint event and will look at where i should move that later(im guessing it need to go up in the form1() area to make sure it is globally visible ?).

    everything works perfectly well in my original setup apart from the flickering, i have suspected it being the update method for a while now but couldnt see why.

  8. #8
    Registered User
    Join Date
    Aug 2008
    Posts
    188
    a) you can't override it because Form is not a subclass of SplitContainer.Panel.
    b) yes, as long as backg is scope-visible

  9. #9
    Registered User
    Join Date
    Oct 2008
    Posts
    85
    ok - here is my main update method - this links to the previously posted Onpaint method.

    Code:
     public void updatemap()
            {
                
                backg = new Bitmap(splitContainer1.Panel2.Width, splitContainer1.Panel2.Height);
                Graphics temp = Graphics.FromImage(backg);
    
               //... do all the graphics drawing etc here
    
                this.Invalidate(); // invalidate area
                this.Update(); // force a redraw
            }
    note : backg is declared as a global.
    going on what Bling said about on declaring the CreatGraphics() once (in the onpaint routine)- can anyone point out where i would implement this call in this method ?

  10. #10
    Registered User
    Join Date
    Aug 2008
    Posts
    188
    every time you call updatemap() you'll just create another Bitmap and Graphics object. even though backg may be global, you're just replacing it with new object every time you call that method. create a bitmap object ONCE.

    if you need it to dynamically resize, listen to the Resize event and properly create a new Bitmap/Graphics pair and Dispose() the old ones.

  11. #11
    Registered User
    Join Date
    Oct 2008
    Posts
    85
    i have added the paint handler and this is working ( using my old code anyway so at least i know i have it set right as per your instructions)

    Backg is now declared in the main form method.

    in the update method i now create :-

    Graphics temp = splitContainer1.Panel2.CreateGraphics();

    and whatever needs doing in there ( however i have disabled the invalidate and update for the moment)

    it works but i can see that i am still drawing directly to the panel2 and my paint handler asks for :-

    e.Graphics.DrawImage(backg, 0, 0);

    how do i set this so whatever i draw on 'Temp' goes to 'Backg'. as backg is global and temp is not and cannot be declared outside of form() as it does not exist before the initialisation ?

    also backg is a bitmap and temp is a graphic.

    or have i just totally got this messed up in my head - really sorry bling

  12. #12
    Registered User
    Join Date
    Aug 2008
    Posts
    188
    i think it'd be worthwhile for you to google some tutorials on how to draw custom controls via C#/.NET.

  13. #13
    Registered User
    Join Date
    Oct 2008
    Posts
    85
    ok - first off apologies to bling - i misunderstood/ misinterpreted what you were saying about the override on the handler and was not overriding the event for the panel2 paint event - this is now rectified.

    it definately draws to panel2 in there now.

    the backg bitmap is declared in the form() as is the graphic for temp. ( this is still not doing what i expect and i will look into it some more later.)

    so apologies to anyone who looks at this and thinks - WHAT THE HELL !!!

    sorry

  14. #14
    Registered User
    Join Date
    Aug 2008
    Posts
    188
    just post the code

  15. #15
    Registered User
    Join Date
    Oct 2008
    Posts
    85
    Code:
    public Form1()
            {
                InitializeComponent();
    
                this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
                this.SetStyle(ControlStyles.UserPaint, true);
                this.SetStyle(ControlStyles.DoubleBuffer, true);
                this.UpdateStyles();
    
                for (int x = 0; x < gridx; x++)  // set initial array to -1 ( for checking purposes)
                    for (int y = 0; y < gridy; y++)
                        Map[x, y] = -1;
    
    
                splitContainer1.Panel2.Paint += painthandler;
    
                ImgList.ImageSize = new Size(32, 32);
                setup_tile_bar();
                do_pictureboxs();
                
               
                backg = new Bitmap(splitContainer1.Panel2.Width, splitContainer1.Panel2.Height);
                temp = splitContainer1.Panel2.CreateGraphics();
                //temp = Graphics.FromImage(backg);
    
                updatemap();
    
                foreach (var PictureBox in mypicturebox)
                {
                    PictureBox.Click += new EventHandler(picClick); // setup eventhandlers for picture boxs
                }
    
            }
    
     public void painthandler(object sender, PaintEventArgs e)
            {
                e.Graphics.Clear(Color.Red);
                e.Graphics.DrawImage(backg, 0, 0);  <-- i believe this is the problem here
                
            }
    
     public void updatemap()
            {
                //draw the grid
    
                for (int i = 0; i < gridx + 1; i++)
                    temp.DrawLine(new Pen(Color.White), new Point(i * 32, 0), new Point(i * 32, (splitContainer1.Panel2.Height)));
                for (int i = 0; i < gridy + 1; i++)
                    temp.DrawLine(new Pen(Color.White), new Point(0, i * 32), new Point((splitContainer1.Panel2.Width), i * 32));
    
                // check map for values outside of current tileset and reset to picturebox 0
                if (ImgList.Images.Count != 0)
                {
                    for (int x = 0; x < gridx; x++) // overlay tile map onto grid
                        for (int y = 0; y < gridy; y++)
                        {
                            if (Map[x, y] >= ImgList.Images.Count)
                                Map[x, y] = 0;  // clear the tile value if no tile exists to replace it
                        }
                }
                
                for (int x = 0; x < gridx; x++) // overlay tile map onto grid
                {
                    for (int y = 0; y < gridy; y++)
                    {
                        imageval = Map[x, y];
    
                        if (imageval >= 0 && ImgList.Images.Count > 0)
                            temp.DrawImage(ImgList.Images[imageval], x * 32, y * 32);
                    }
                }
    
                if (dragging)
                {
                    int tempstartx = rectstartx; // temp variables so as not to corrupt actual start and end co-ords!
                    int tempstarty = rectstarty;
                    int width = rectendx - rectstartx;
                    int height = rectendy - rectstarty;
    
                    if (rectstartx > rectendx)
                        width = rectstartx - rectendx;
                    if (rectstarty > rectendy)
                        height = rectstarty - rectendy;
    
                    if (rectstartx > rectendx) //swap start to end if end is less than start
                    {
                        tempstartx = rectendx;
                    }
    
                    if (rectstarty > rectendy)
                    {
                        tempstarty = rectendy;
                    }
                    temp.DrawRectangle(Pens.White, tempstartx, tempstarty, width, height);
    
                }
    
                this.Invalidate(); // invalidate area
                this.Update(); // force a redraw
            }
    here are the relevant sections that deal with the drawing and updates.

    hope this helps - it si definatley an issue where the rendered section is not being rendered back to panel2. but i cnat see where or why

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. MoA Updates
    By harryp in forum C++ Programming
    Replies: 0
    Last Post: 08-31-2002, 10:28 AM
  2. Graphic screen redraw
    By bob5845 in forum C++ Programming
    Replies: 0
    Last Post: 04-09-2002, 08:45 PM
  3. graphic library creation
    By bob5845 in forum C++ Programming
    Replies: 1
    Last Post: 04-05-2002, 12:30 AM
  4. Do you still need a graphic card if you're just using something like dos?
    By Nutshell in forum A Brief History of Cprogramming.com
    Replies: 5
    Last Post: 03-26-2002, 12:09 PM
  5. DOS graphic viewer
    By Unregistered in forum A Brief History of Cprogramming.com
    Replies: 0
    Last Post: 02-24-2002, 04:00 AM