Creating and placing images/graphics on a panel

I'm creating a graphic, later to be a photo, and placing it onto a
panel. While this works fine in itself, there are annoying artifacts
during subsequent frame resizings. A wx.StaticBitmap is created to
hold the image.

Would creating a custom bitmapped button or frame eliminate the
"ghosts" of all the old images ? Is there a "prescribed" technique ?

(running 32-bit python/Pil/wxPython on 64-bit Win7)

···

==================================================

import wx
import Image # rectangle image creation
import random # rectangle colors

#--------------------------------------------------------------------

class MainFrame( wx.Frame ):

    def __init__( self, parent, id, title ):

        wx.Frame.__init__( self, parent,-4, title, size=(400, 400),
pos=(800, 100),
                           style=wx.DEFAULT_FRAME_STYLE )

        self.panel = wx.Panel( self, -1 )
        self.backgroundColor = NewRandomColor()
        self.panel.SetBackgroundColour( self.backgroundColor )

        self.currClientSizePrev = self.GetClientSize() # Init

        self.Show( True )

        #--------------------

        # Overlay a bordered rectangle on the panel
        # after a retriggerable one-shot timeout and
        # after the last resize event. This avoids unecessary
redraws.
        self.hasBeenResized = False
        self.Bind( wx.EVT_SIZE, self.OnSize ) # this event only sets
a redraw flag

        self.timer = wx.Timer( self ) # redraw only on
timeout and redraw flag is set
        self.Bind (wx.EVT_TIMER, self.OnTimer )
        self.timerInterval = 200 #
delay value chosen heuristically
        self.timer.Start( self.timerInterval, oneShot=True ) #
Enable one-shot timer IRQ's

    #end def __init__

    #---------------------------------------------

    def DisplayBorderedRectangle( self, size, color, pos ):

        if ( (size[0] > 0) and (size[1] > 0) ) :

            imgblank = Image.new( 'RGB', size )
            margin = 2 # Leave a
black border
            imgblank.paste( color, (margin, margin,
                                    size[0]-margin, size[1]-margin ) )

            imgdata = imgblank.tostring( 'raw', 'RGB' )
            emptyimage = wx.EmptyImage( size[0], size[1] ) # An
image display container
            emptyimage.SetData( imgdata ) # data
conversion
            self.blankbitmap = emptyimage.ConvertToBitmap()

            wx.StaticBitmap( self.panel, -1, self.blankbitmap,
                                             size=size, pos=pos )

            self.panel.Refresh()

        #end if

    #end def

    #--------------------------------------------

    def OnSize( self, event ):

        currClientSize = self.GetClientSize()
        if ( currClientSize != self.currClientSizePrev ) :

            self.hasBeenResized = True
            self.currClientSizePrev = currClientSize

            self.timer.Start( self.timerInterval,
oneShot=True )

        #end if

        event.Skip( True )

    #end def

    #--------------------------------------------

    def OnTimer( self, event ):

        if self.hasBeenResized :

            # Display a new graphic
            currClientSize = self.GetClientSize()
            currClientSizeX, currClientSizeY = (currClientSize[0],
currClientSize[1])

            reductionBorderX = 30
            reductionBorderX, reductionBorderY = (25, 25)

            newImageSizeX = currClientSizeX - reductionBorderX
            newImageSizeY = currClientSizeY - reductionBorderY
            newImageSize = ( newImageSizeX, newImageSizeY )
            newImagePos = ( reductionBorderX/2, reductionBorderY/2 )

            newImageColor = NewRandomColor()

            # "Erase" the viewable area
            self.DisplayBorderedRectangle( currClientSize,
self.backgroundColor, (0, 0) )
            # Paint the new graphic
            self.DisplayBorderedRectangle( newImageSize,
newImageColor, newImagePos )

            self.hasBeenResized = False # make ready for next
resize/repaint

        #end if

        self.timer.Start( self.timerInterval, oneShot=True )

        event.Skip( True )

    #end def

#end class MainFrame

#------------------------------------------------------------------------------

def NewRandomColor():

    return (random.randint(0, 255), random.randint(0, 255),
random.randint(0, 255))

#end def

#==============================================================================

MyApp = wx.PySimpleApp( False ) # Send errors to command window, not
a pop-up.
MyFrame = MainFrame( None, -1, 'Image Fit' )
MyApp.MainLoop()

--
To unsubscribe, send email to wxPython-users+unsubscribe@googlegroups.com
or visit http://groups.google.com/group/wxPython-users?hl=en

I think you just need to call self.panel.Layout() after the resize is done (so put that near the end of OnTimer(). If the flickering is annoying, add a Freeze() and Thaw() around the resizing code to see if that helps.

···

On Thu, Apr 22, 2010 at 11:45 AM, WinCrazy pascor@verizon.net wrote:

I’m creating a graphic, later to be a photo, and placing it onto a

panel. While this works fine in itself, there are annoying artifacts

during subsequent frame resizings. A wx.StaticBitmap is created to

hold the image.

Would creating a custom bitmapped button or frame eliminate the

“ghosts” of all the old images ? Is there a “prescribed” technique ?

(running 32-bit python/Pil/wxPython on 64-bit Win7)

Mike Driscoll

Blog: http://blog.pythonlibrary.org

To unsubscribe, send email to wxPython-users+unsubscribe@googlegroups.com

or visit http://groups.google.com/group/wxPython-users?hl=en

Neither suggestions work, even when used together. Apparently, there
is a DC-like object that does not get cleared out. I made a
wx.BitmapButton to get a borderless frame around it. Even deleting and
recreating the panel+button changes nothing.

When resizing, all the previous bitmaps are redrawn in order which
makes the refresh longer as the number of user's resizes increase
( like a DC ).

? Is there actually a DC buried in the wxWidget code that can be
accessed in order to delete all it's drawing objects ?

If not, I will have to resort to destroying and then recreating the
whole frame to achieve what I think should be the expected operation.
This seems like an incredible waste of CPU cycles - imagine if the
main frame is very complicated !

···

On Apr 22, 3:19 pm, Mike Driscoll <m...@pythonlibrary.org> wrote:

On Thu, Apr 22, 2010 at 11:45 AM, WinCrazy <pas...@verizon.net> wrote:
> I'm creating a graphic, later to be a photo, and placing it onto a
> panel. While this works fine in itself, there are annoying artifacts
> during subsequent frame resizings. A wx.StaticBitmap is created to
> hold the image.

> Would creating a custom bitmapped button or frame eliminate the
> "ghosts" of all the old images ? Is there a "prescribed" technique ?

> (running 32-bit python/Pil/wxPython on 64-bit Win7)

<code snipped>

I think you just need to call self.panel.Layout() after the resize is done
(so put that near the end of OnTimer(). If the flickering is annoying, add a
Freeze() and Thaw() around the resizing code to see if that helps.

--
-----------------
Mike Driscoll

Blog: http://blog.pythonlibrary.org

--
To unsubscribe, send email to wxPython-users+unsubscribe@googlegroups.com
or visithttp://groups.google.com/group/wxPython-users?hl=en

--
To unsubscribe, send email to wxPython-users+unsubscribe@googlegroups.com
or visit http://groups.google.com/group/wxPython-users?hl=en

Hi,

Neither suggestions work, even when used together. Apparently, there
is a DC-like object that does not get cleared out. I made a
wx.BitmapButton to get a borderless frame around it. Even deleting and
recreating the panel+button changes nothing.

When resizing, all the previous bitmaps are redrawn in order which
makes the refresh longer as the number of user's resizes increase
( like a DC ).

? Is there actually a DC buried in the wxWidget code that can be
accessed in order to delete all it's drawing objects ?

If not, I will have to resort to destroying and then recreating the
whole frame to achieve what I think should be the expected operation.
This seems like an incredible waste of CPU cycles - imagine if the
main frame is very complicated !

My suggestion would be not to use a wx.StaticBitmap or a
wx.BitmapButton, but to draw the image yourself in the control. As an
example (hiiiiighly untested):

class PaintMePanel(wx.Panel):

    def __init__(self, parent, bitmap):

        wx.Panel.__init__(self, parent)
        self.bitmap = bitmap

        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnErase)

    def OnPaint(self, event):

        dc = wx.BufferedPaintDC(self)
        dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
        dc.Clear()

        dc.DrawBitmap(0, 0, self.bitmap)

     def OnSize(self, event):

        event.Skip()
        self.Refresh()

    def OnErase(self, event):

        pass

Something along these lines. The code is highly approximated as I just
wrote it down on Gmail, but it should give you a start.

Andrea.

"Imagination Is The Only Weapon In The War Against Reality."
http://xoomer.alice.it/infinity77/

==> Never *EVER* use RemovalGroup for your house removal. You'll
regret it forever.
The Doomed City: Removal Group: the nightmare <==

···

On 23 April 2010 18:31, WinCrazy wrote:

--
To unsubscribe, send email to wxPython-users+unsubscribe@googlegroups.com
or visit http://groups.google.com/group/wxPython-users?hl=en

No. wx.StaticBitmap is not a "drawing object" it is a window or widget. It sounds like you are creating a new wx.StaticBitmap (or is it wx.BitmapButton now?) for each new image you want to display, and so what you are seeing is each of them repainting itself. Don't do that. Just create one and call its SetBitmap method when you want to display a new image.

···

On 4/23/10 10:31 AM, WinCrazy wrote:

Neither suggestions work, even when used together. Apparently, there
is a DC-like object that does not get cleared out. I made a
wx.BitmapButton to get a borderless frame around it. Even deleting and
recreating the panel+button changes nothing.

When resizing, all the previous bitmaps are redrawn in order which
makes the refresh longer as the number of user's resizes increase
( like a DC ).

? Is there actually a DC buried in the wxWidget code that can be
accessed in order to delete all it's drawing objects ?

--
Robin Dunn
Software Craftsman

--
To unsubscribe, send email to wxPython-users+unsubscribe@googlegroups.com
or visit http://groups.google.com/group/wxPython-users?hl=en

The optimal solution I found was to use a wx.ClientDC. The very few DC
examples I found used a DC in the wrong ways. Only derived classes of
wx.DC should ever be used according to the documentation.

···

----------------------------------------------------------------------------
On Apr 23, 3:30 pm, Robin Dunn <ro...@alldunn.com> wrote:

On 4/23/10 10:31 AM, WinCrazy wrote:

> Neither suggestions work, even when used together. Apparently, there
> is a DC-like object that does not get cleared out. I made a
> wx.BitmapButton to get a borderless frame around it. Even deleting and
> recreating the panel+button changes nothing.

> When resizing, all the previous bitmaps are redrawn in order which
> makes the refresh longer as the number of user's resizes increase
> ( like a DC ).

> ? Is there actually a DC buried in the wxWidget code that can be
> accessed in order to delete all it's drawing objects ?

No. wx.StaticBitmap is not a "drawing object" it is a window or widget.
It sounds like you are creating a new wx.StaticBitmap (or is it
wx.BitmapButton now?) for each new image you want to display, and so
what you are seeing is each of them repainting itself. Don't do that.
Just create one and call its SetBitmap method when you want to display a
new image.

--
Robin Dunn
Software Craftsmanhttp://wxPython.org

--
To unsubscribe, send email to wxPython-users+unsubscribe@googlegroups.com
or visithttp://groups.google.com/group/wxPython-users?hl=en

--
To unsubscribe, send email to wxPython-users+unsubscribe@googlegroups.com
or visit http://groups.google.com/group/wxPython-users?hl=en