Maddening Custom Control Flicker

Do you catch EVT_ERASE_BACKGROUND and do nothing? If not that is a good
place to start. As long as you are updating all parts of the window it
should have no side-effects.

Will McGugan

From: Jason Johnson [mailto:jasonj@ivieinc.com]
Sent: 29 September 2006 16:36
To: wxpython-users@lists.wxwidgets.org
Subject: [wxPython-users] Maddening Custom Control Flicker

Hey all -

I've built a decent image thumbnail viewer as a custom control which
inherits wx.Panel. It's roughly based on some of the techniques used

in

Andrea Gavana's ThumbnailCtrl. Mine currently can handle tens of
thousands of thumbnails efficiently, but I've achieved this by
eliminating two key elements of Andrea's control -- smooth scrolling

and

no flickering.

In the OnPaint for my control, I have this:
    paint = wx.PaintDC(self)
    paint.BeginDrawing()
    # Set pens, draw rects and bmp thumbs, swap pens for 'selected'
items, etc.
    paint.EndDrawing()

Now, this is where my horrific (and headache-inducing) side effect

comes

in.

In the OnResize, I have this (don't scream):
    self.Refresh()

The control flickers like mad. I mean, certifiably mad. Every

movement,

every click, every resize -- it's unbearable. But the product is
extraordinarily fast and effective! Multiple select! Drag and drop and
everything! My question to you is this: is there any way to transition
from the current paint buffer to the next smoothly and efficiently and
eliminate most, if not all, the flicker? More or less like
double-buffering in a video game kind of way?

I fully plan to post the source for everyone to pick apart once this
problem has been eliminated -- really don't want to disseminate code
which easily causes headaches and such. Any help would be much
appreciated!

- Jason

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwidgets.org
For additional commands, e-mail:

wxPython-users-help@lists.wxwidgets.org

···

-----Original Message-----

Will -

I've just added this bound to EVT_ERASE_BACKGROUND:

def OnEraseBackground(self, event):
        pass

That helps a lot with the flickering, but (I think) because the control is nested in a couple SplitterWindows, a bunch of artifacts are left after a resize and actually even after window creation -- ghosts of windows from other applications are actually part of the background.

Knowing this curbs the flickering of the control, does this help in knowing what may be causing the problem?

What I have been mulling over is the fact that Andrea uses MemoryDC to render the thumbnails, where I'm using a PaintDC directly in the OnPaint method. Should I try and swap that out and have it draw the entire thing in memory? I'm assuming this is what MemoryDC would accomplish.

- Jason

Will McGugan wrote:

···

Do you catch EVT_ERASE_BACKGROUND and do nothing? If not that is a good
place to start. As long as you are updating all parts of the window it
should have no side-effects.

Will McGugan

-----Original Message-----
From: Jason Johnson [mailto:jasonj@ivieinc.com]
Sent: 29 September 2006 16:36
To: wxpython-users@lists.wxwidgets.org
Subject: [wxPython-users] Maddening Custom Control Flicker

Hey all -

I've built a decent image thumbnail viewer as a custom control which
inherits wx.Panel. It's roughly based on some of the techniques used
    

in
  

Andrea Gavana's ThumbnailCtrl. Mine currently can handle tens of
thousands of thumbnails efficiently, but I've achieved this by
eliminating two key elements of Andrea's control -- smooth scrolling
    

and
  

no flickering.

In the OnPaint for my control, I have this:
    paint = wx.PaintDC(self)
    paint.BeginDrawing()
    # Set pens, draw rects and bmp thumbs, swap pens for 'selected'
items, etc.
    paint.EndDrawing()

Now, this is where my horrific (and headache-inducing) side effect
    

comes
  

in.

In the OnResize, I have this (don't scream):
    self.Refresh()

The control flickers like mad. I mean, certifiably mad. Every
    

movement,
  

every click, every resize -- it's unbearable. But the product is
extraordinarily fast and effective! Multiple select! Drag and drop and
everything! My question to you is this: is there any way to transition
from the current paint buffer to the next smoothly and efficiently and
eliminate most, if not all, the flicker? More or less like
double-buffering in a video game kind of way?

I fully plan to post the source for everyone to pick apart once this
problem has been eliminated -- really don't want to disseminate code
which easily causes headaches and such. Any help would be much
appreciated!

- Jason

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwidgets.org
For additional commands, e-mail:
    

wxPython-users-help@lists.wxwidgets.org

---------------------------------------------------------------------
To unsubscribe, e-mail: wxPython-users-unsubscribe@lists.wxwidgets.org
For additional commands, e-mail: wxPython-users-help@lists.wxwidgets.org

Jason Johnson wrote:

Will -

I've just added this bound to EVT_ERASE_BACKGROUND:

def OnEraseBackground(self, event):
       pass

That helps a lot with the flickering, but (I think) because the control is nested in a couple SplitterWindows, a bunch of artifacts are left after a resize and actually even after window creation -- ghosts of windows from other applications are actually part of the background.

This sounds like you are not fully painting the exposed or damaged regions of the window. You can get around this by either painting the full window, or use GetUpdateRegion to find out the portions that need to be refreshed and paint them.

Knowing this curbs the flickering of the control, does this help in knowing what may be causing the problem?

The default EVT_ERASE_BACKGROUND simply paints the full window with the current background colour, clearing what you painted before. Then the EVT_PAINT event happens and you paint your content again. So the flicker comes from always clearing and repainting your content.

What I have been mulling over is the fact that Andrea uses MemoryDC to render the thumbnails, where I'm using a PaintDC directly in the OnPaint method. Should I try and swap that out and have it draw the entire thing in memory? I'm assuming this is what MemoryDC would accomplish.

Yes. It allows you to do all your drawing to a bitmap, and then at the time of the paint event all you need to do is blit the bitmap to the window. This speeds up your EVT_PAINT since it already has the content drawn, and since there is only a single operation needed to put the content out to the screen. There are also the wx.BufferedDC and wx.BufferedPaintDC convenience classes that make this a little easier.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!