Flicker drawing with GDI+

I wrote a scrolling text marquee that renders text into a memory buffer (a System.Drawing.Bitmap) and uses a timer to update the scrolling text by rendering the buffer with Graphics.DrawImage.

I have tried everything and no matter what I always get flickers.

I enabled double buffering:

this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
this.UpdateStyles();


The Graphics object is created from a panel, which is used as canvas.

_oGraphics = oDest.CreateGraphics(); // oDest is a System.Windows.Forms.Panel


I created a memory buffer for the background and

// render the buffer
_oGraphics.DrawImage(_oImageBackground, 0, 0);

// Render canvas
if(_oCanvas != null)
     _oGraphics.DrawImage(_oCanvas.Canvas, _iCursor, 0);


Clearing the Graphics object is worse. I'm at loss...


Refresh is based on a timer at a 30 millisecond interval and _iCursor moves 2 pixels at a time. Display is otherwise smooth.


Thanks,
Rich.
LVL 1
mannycalaverasAsked:
Who is Participating?
 
PAQ_ManCommented:
Question Closed, 200 points refunded.
PAQ_Man
Community Support Moderator
0
 
smeggheadCommented:
Where is your code for refreshing ?

Have you tried putting the code for 'drawimage' in the Paint event of the control, then calling invalidate() for that control, that will cause the paint event to be fired, which contains the relevant graphics object. It might be that the panel is refreshing itself anyway.

Smg.
0
 
mannycalaverasAuthor Commented:
// Code for refreshing, called by
gr.DrawImage(_oImageBackground, 0, 0);

if(_oCanvas != null)
      gr.DrawImage(_oCanvas.Canvas, _iCursor, 0);


I tried calling invalidate on the Panel in the timer Tick and using the control's Graphics object but it didn't work either.

Next try... refresh thread...
0
Cloud Class® Course: Ruby Fundamentals

This course will introduce you to Ruby, as well as teach you about classes, methods, variables, data structures, loops, enumerable methods, and finishing touches.

 
mannycalaverasAuthor Commented:
Refresh thread obviously did not make a difference...

Here's my refresh method

public void Render(/*System.Drawing.Graphics gr*/)
{
      do
      {
            try
            {
                  if(_bRunning && _oGraphics != null && _oCanvas != null)
                  {
                              _oGraphics.DrawImage(_oImageBackground, 0, 0); // oImageBackground is a System.Drawing.Bitmap
                        _oGraphics.DrawImage(_oCanvas.Canvas, _iCursor, 0); // Canvas is a System.Drawing.Bitmap

                        if((_iCursor = _iCursor-2) < -Convert.ToInt32(_oCanvas.Width))
                              _iCursor = Convert.ToInt32(_width);
                  }

                  Thread.Sleep(1000 / _iInterval);
            }
            catch(Exception/* ex*/)
            {
                  //clsUtils.NotifyException(ex);
                  Thread.CurrentThread.Abort();
            }
      }
      while(true);
}
0
 
smeggheadCommented:
Are you able to email me your code? my address is in my profile.
0
 
AgariciCommented:
i think somewere in your code the background gets erased

so i would say it is worth trying this:

add an override to wndproc and handle the erase background there
protected override void WndProc(ref Message messg)
{
        // We do not want to erase the background,
        if ((int)WM.WM_ERASEBKGND == messg.Msg)
            messg.Msg = (int) WM.WM_NULL;
 
        base.WndProc(ref messg);
}


hth,
A.
0
 
Bob LearnedCommented:
You could add the ControlStyles.UserPaint, and use the Paint event (persistent), instead of using CreateGraphics (non-persistent).

Bob
0
 
mannycalaverasAuthor Commented:
Tried blocking the WM_ERASEBKGND for the panel control or the main window and it did not help.

I already tried using the Graphics object from the OnPaint message without any difference.

Problem seems to be that double buffering or any other display setting doesn't seem to be working.

This is supposed to turn on double buffering as well as styles that minimize flickering...

this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.AllPaintingInWmPaint |
      ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true);
this.UpdateStyles();


But it doesn't do anything. Whether I put this or not doesn't change anything.
0
 
smeggheadCommented:
Have you overridden the OnPaintBackground

            protected override void OnPaintBackground(PaintEventArgs e)
            {
                  // This section should be left blank - so that it doesn't draw the background..
                  //base.OnPaintBackground(e);
            }
0
 
_TAD_Commented:

Take a look at this link:
http://www.codeproject.com/cs/media/sprites.asp

This link actually refers to moving sprites/animated graphics, but it may hold the key to a flickerless scrolling textbox for you.

In a nutshell, it uses rectangles and only refreshes a small region.  At any rate, take look... at worst it will cost you 20 minutes of your life.  I found it rather interesting and easy to follow.
0
 
mannycalaverasAuthor Commented:
Yes. I have found the problem.

Rendering on the panel caused the problem.

The idea was to have the panel as a delimiter for the canvas.

Double buffering is enabled on the main application and controls do not support double buffering, only the main app.

So instead I use the panel as a bounding box, invisible, and display on the main application's using the panel's bounds as limits.

All examples I found used the main form window as render area so the case was never handled. There might be a way to enable double buffering on individual controls, however the SetStyle requires to be called from a Control control, which only the application window is.

Don't understand why it's not possible for any control as they windows anyway.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.