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

Hello Jason,

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,

I am curious to see your new control, it's time to have a good alternative to my somewhat approximative ThumbnailCtrl :smiley:

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!

Other than the suggestion Will has given, I would say: are you refreshing *everything* in the OnPaint() event? A ThumbnailCtrl shows 5, 10, 15 thumbnails at a time (as a mean value, unless it occupies all the screen), so there is no need to refresh all the thumbnails if they are not visible. Basically, once you know the position of a thumbnail and you have the wx.Rect() of your visible portion of ThumbnailCtrl, you can see if the wx.Rect() intersect that position or not: if it doesn't intersect, no need to paint that thumbnail.

Andrea.

···

_________________________________________
Andrea Gavana (gavana@kpo.kz)
Reservoir Engineer
KPDL
4, Millbank
SW1P 3JA London

Direct Tel: +44 (0) 20 717 08936
Mobile Tel: +44 (0) 77 487 70534
Fax: +44 (0) 20 717 08900
Web: http://xoomer.virgilio.it/infinity77
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯

Andrea!

First, I owe you a load of thanks. Your control has helped tremendously, and as I said, I will post the code to my control shortly under the same license.

In a nutshell, I'll recap the logic I'm using to render the control:

Because I've swapped out your choice of wx.ScrolledWindow with wx.Panel, it appears I've cornered a lot of the efficiency problems when handling massive sets of thumbnails -- simply honing the scope of what can even be rendered. But onto the innards..

I grab the ClientSize of the Panel and calculate the number of Columns and Rows which would be visible based on the current size of thumbnails and additional padding between each thumb (exceeding the Row count by 1x to account for a scroll-like effect). I then gather a variable Offset for the view and calculate which subset of the entire thumbnail list (which is simply a list of the contents of a specified directory) should be rendered -- effectively producing a paging mechanism which is externally modifiable through the Offset. Finally, once this is all calculated, I range through the Rows and Columns, Pen out the Rectangles and fill in the Bitmaps with their respective coordinates and close out the Drawing.

If you wrap the whole thing in a SplitterWindow next to a ScrollBar and hook up the Offset mutators, it emulates your interface to a degree... but is not yet acceptable.

So, to answer your question I'm fairly certain the control is only attempting to render what I've told it to -- only what is visible (though I could be wrong, I've been pretty deep in it for the past few days).

I will spend the remainder of the day cleaning up what I have and post it as soon as possible. I would very much like to get your feedback.

Many thanks.

- Jason

Gavana, Andrea wrote:

···

Hello Jason,

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,
    
I am curious to see your new control, it's time to have a good alternative to my somewhat approximative ThumbnailCtrl :smiley:

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!
    
Other than the suggestion Will has given, I would say: are you refreshing *everything* in the OnPaint() event? A ThumbnailCtrl shows 5, 10, 15 thumbnails at a time (as a mean value, unless it occupies all the screen), so there is no need to refresh all the thumbnails if they are not visible. Basically, once you know the position of a thumbnail and you have the wx.Rect() of your visible portion of ThumbnailCtrl, you can see if the wx.Rect() intersect that position or not: if it doesn't intersect, no need to paint that thumbnail.

Andrea.

_________________________________________
Andrea Gavana (gavana@kpo.kz)
Reservoir Engineer
KPDL
4, Millbank
SW1P 3JA London
Direct Tel: +44 (0) 20 717 08936
Mobile Tel: +44 (0) 77 487 70534
Fax: +44 (0) 20 717 08900
Web: http://xoomer.virgilio.it/infinity77
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯

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

Well…

paint on an offscreen MemoryDC and when you’re done painting blit the result on the PaintDC.

My version of the thumbnailer used something like this… you can look in the list’s archive for it :wink:

Peter

···

On 9/29/06, Jason Johnson jasonj@ivieinc.com wrote:

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()

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?


There is NO FATE, we are the creators.