Trying to modify part of image by layering bitmaps

Hope you kind folk can spare a bit of advice. I'm trying to find a
clever way to modifying a part of an image without replacing the image
completely. For instance, let's say I have an image of a car and I
would like to show the tire is flat. Instead of replacing the image
completely with another, I would like to layer a new image of a flat
tire image on top of current tire image. Eventually I would like to
extend this to show multiple stats of the car, flat tires, ajar doors,
headlight burnt out, etc etc. Since each of these stats can occur
independently, just replacing one entire image for each combination of
stats is crazy inefficient.

I've been using a bit of code that layers a bitmap (with a transparent
background) on top another. What I'm not sure about is how to modify
the layered images. Let's say I have 5 smaller images layered on top
of the large car image, is there a way I can change the bitmap of one
of the layered images in real time and delete those I no longer wish
to display?

In the below code, I draw the "low_tire.png" image on top the
"car.png". Then when the button is clicked I would like the
"low_tire.png" to be changed with the "flat_tire.png" image. How would
I accomplish this? And how would I delete the layered image
completely?

Here's my code thus far:

[CODE]
import wx

class Frame1(wx.Frame):
    def __init__(self, prnt):
        wx.Frame.__init__(self, id=-1, name='', parent=prnt,
              pos=wx.Point(0, 0), size=wx.Size(600, 600),
              style=wx.DEFAULT_FRAME_STYLE, title='Frame1')
        self.panel1 = BmpPanel(self)
        self.Show()

class BmpPanel(wx.Panel):
    def __init__(self, parent, id = -1):
        wx.Panel.__init__(self, parent, id)

        self.Bind(wx.EVT_PAINT, self.OnPaint)

        self.button = wx.Button(self, id, 'click to change layered
image')
        self.Bind(wx.EVT_BUTTON, self.modTheImage,
id=self.button.GetId())

        self.BackBmp = wx.Bitmap('car.png')
        self.FrontBmp = wx.Bitmap('low_tire.png')
        self.hiBmp = wx.Bitmap('door_ajar.png')

    def OnPaint(self, event):
        self.dc = wx.PaintDC(self)
        self.Update()

    def Update(self):
        self.dc.DrawBitmap(self.BackBmp, 96, 72, True)
        self.dc.DrawBitmap(self.FrontBmp, 150, 110, True)

    def modTheImage(self, event):
        self.FrontBmp = wx.Bitmap('flat_tire.png') # ATTEMPT TO CHANCE
IMAGE FILE (DOES NOT WORK)
        #self.Update
        #self.Refresh() # USING THIS SEEMS TO CRASH THE APPLICATION

App = wx.PySimpleApp()
application = Frame1(None)
application.Show()
App.MainLoop()
[/CODE]

Thanks all!

Whoops, just found a quick typo. Should be:

    def modTheImage(self, event):
        self.dc.Clear()
        self.FrontBmp = wx.Bitmap('flat_tire.png')
        self.Update() # Forgot the brackets! :slight_smile:

which does indeed replace the image. Still looking for a way to delete
an image, and of course any suggestions if anyone has any!

···

On Dec 2, 10:06 pm, Convoluted <xenon...@gmail.com> wrote:

Hope you kind folk can spare a bit of advice. I'm trying to find a
clever way to modifying a part of an image without replacing the image
completely. For instance, let's say I have an image of a car and I
would like to show the tire is flat. Instead of replacing the image
completely with another, I would like to layer a new image of a flat
tire image on top of current tire image. Eventually I would like to
extend this to show multiple stats of the car, flat tires, ajar doors,
headlight burnt out, etc etc. Since each of these stats can occur
independently, just replacing one entire image for each combination of
stats is crazy inefficient.

I've been using a bit of code that layers a bitmap (with a transparent
background) on top another. What I'm not sure about is how to modify
the layered images. Let's say I have 5 smaller images layered on top
of the large car image, is there a way I can change the bitmap of one
of the layered images in real time and delete those I no longer wish
to display?

In the below code, I draw the "low_tire.png" image on top the
"car.png". Then when the button is clicked I would like the
"low_tire.png" to be changed with the "flat_tire.png" image. How would
I accomplish this? And how would I delete the layered image
completely?

Here's my code thus far:

[CODE]
import wx

class Frame1(wx.Frame):
def __init__(self, prnt):
wx.Frame.__init__(self, id=-1, name='', parent=prnt,
pos=wx.Point(0, 0), size=wx.Size(600, 600),
style=wx.DEFAULT_FRAME_STYLE, title='Frame1')
self.panel1 = BmpPanel(self)
self.Show()

class BmpPanel(wx.Panel):
def __init__(self, parent, id = -1):
wx.Panel.__init__(self, parent, id)

    self\.Bind\(wx\.EVT\_PAINT, self\.OnPaint\)

    self\.button = wx\.Button\(self, id, &#39;click to change layered

image')
self.Bind(wx.EVT_BUTTON, self.modTheImage,
id=self.button.GetId())

    self\.BackBmp = wx\.Bitmap\(&#39;car\.png&#39;\)
    self\.FrontBmp = wx\.Bitmap\(&#39;low\_tire\.png&#39;\)
    self\.hiBmp = wx\.Bitmap\(&#39;door\_ajar\.png&#39;\)

def OnPaint\(self, event\):
    self\.dc = wx\.PaintDC\(self\)
    self\.Update\(\)

def Update\(self\):
    self\.dc\.DrawBitmap\(self\.BackBmp, 96, 72, True\)
    self\.dc\.DrawBitmap\(self\.FrontBmp, 150, 110, True\)

def modTheImage\(self, event\):
    self\.FrontBmp = wx\.Bitmap\(&#39;flat\_tire\.png&#39;\) \# ATTEMPT TO CHANCE

IMAGE FILE (DOES NOT WORK)
#self.Update
#self.Refresh() # USING THIS SEEMS TO CRASH THE APPLICATION

App = wx.PySimpleApp()
application = Frame1(None)
application.Show()
App.MainLoop()
[/CODE]

Thanks all!

From: Convoluted

Sent: Friday, December 03, 2010 6:27 AM

To: wxPython-users

Subject: [wxPython-users] Re: Trying to modify part of image by layering bitmaps

Whoops, just found a quick typo. Should be:

def modTheImage(self, event):

self.dc.Clear()

self.FrontBmp = wx.Bitmap(‘flat_tire.png’)

self.Update() # Forgot the brackets! :slight_smile:

which does indeed replace the image. Still looking for a way to delete

an image, and of course any suggestions if anyone has any!

Of course you could always replace the image with a completely transparent one, while this does not free up the resources it does mean that you are reserving the same resources all the time this should make things more responsive.

Gadget/Steve

···

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

On Dec 2, 10:06 pm, Convoluted xenon...@gmail.com wrote:

Hope you kind folk can spare a bit of advice. I’m trying to find a

clever way to modifying a part of an image without replacing the image

completely. For instance, let’s say I have an image of a car and I

would like to show the tire is flat. Instead of replacing the image

completely with another, I would like to layer a new image of a flat

tire image on top of current tire image. Eventually I would like to

extend this to show multiple stats of the car, flat tires, ajar doors,

headlight burnt out, etc etc. Since each of these stats can occur

independently, just replacing one entire image for each combination of

stats is crazy inefficient.

I’ve been using a bit of code that layers a bitmap (with a transparent

background) on top another. What I’m not sure about is how to modify

the layered images. Let’s say I have 5 smaller images layered on top

of the large car image, is there a way I can change the bitmap of one

of the layered images in real time and delete those I no longer wish

to display?

In the below code, I draw the “low_tire.png” image on top the

“car.png”. Then when the button is clicked I would like the

“low_tire.png” to be changed with the “flat_tire.png” image. How would

I accomplish this? And how would I delete the layered image

completely?

Here’s my code thus far:

[CODE]

import wx

class Frame1(wx.Frame):

def __init__(self, prnt):
    wx.Frame.__init__(self, id=-1, name='', parent=prnt,
          pos=wx.Point(0, 0), size=wx.Size(600, 600),
          style=wx.DEFAULT_FRAME_STYLE, title='Frame1')
    self.panel1 = BmpPanel(self)
    self.Show()

class BmpPanel(wx.Panel):

def __init__(self, parent, id = -1):
    wx.Panel.__init__(self, parent, id)
    self.Bind(wx.EVT_PAINT, self.OnPaint)
    self.button = wx.Button(self, id, 'click to change layered

image’)

    self.Bind(wx.EVT_BUTTON, self.modTheImage,

id=self.button.GetId())

    self.BackBmp = wx.Bitmap('car.png')
    self.FrontBmp = wx.Bitmap('low_tire.png')
    self.hiBmp = wx.Bitmap('door_ajar.png')
def OnPaint(self, event):
    self.dc = wx.PaintDC(self)
    self.Update()
def Update(self):
    self.dc.DrawBitmap(self.BackBmp, 96, 72, True)
    self.dc.DrawBitmap(self.FrontBmp, 150, 110, True)
def modTheImage(self, event):
    self.FrontBmp = wx.Bitmap('flat_tire.png') # ATTEMPT TO CHANCE

IMAGE FILE (DOES NOT WORK)

    #self.Update
    #self.Refresh() # USING THIS SEEMS TO CRASH THE APPLICATION

App = wx.PySimpleApp()

application = Frame1(None)

application.Show()

App.MainLoop()

[/CODE]

Thanks all!

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

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

Interesting thought Steve, I'll have to give that a try.

There's also something amiss with the code. When displaying two
images, one layered on top another, hovering over the images rapidly
leads to fairly minimal CPU usage, however if I switch to another
window and back, the images begin flickering madly and CPU usage maxes
out. Also, if I enable double buffering, hovering over the images
rapidly leads to around 30% CPU usage. I'm not sure what's going. I
don't have these problems with staticBitmaps and double buffering. It
seems that wx.EVT_PAINT is being called very frequently for some
reason. Is there a way to eliminate this?

···

On Dec 2, 11:44 pm, Steve Barnes <GadgetSt...@live.co.uk> wrote:

-----Original Message-----
From: Convoluted
Sent: Friday, December 03, 2010 6:27 AM
To: wxPython-users
Subject: [wxPython-users] Re: Trying to modify part of image by layering bitmaps

Whoops, just found a quick typo. Should be:

  def modTheImage\(self, event\):
      self\.dc\.Clear\(\)
      self\.FrontBmp = wx\.Bitmap\(&#39;flat\_tire\.png&#39;\)
      self\.Update\(\) \# Forgot the brackets\! :\)

which does indeed replace the image. Still looking for a way to delete
an image, and of course any suggestions if anyone has any!

Of course you could always replace the image with a completely transparent one, while this does not free up the resources it does mean that you are reserving the same resources all the time this should make things more responsive.

Gadget/Steve

On Dec 2, 10:06 pm, Convoluted <xenon...@gmail.com> wrote:
> Hope you kind folk can spare a bit of advice. I'm trying to find a
> clever way to modifying a part of an image without replacing the image
> completely. For instance, let's say I have an image of a car and I
> would like to show the tire is flat. Instead of replacing the image
> completely with another, I would like to layer a new image of a flat
> tire image on top of current tire image. Eventually I would like to
> extend this to show multiple stats of the car, flat tires, ajar doors,
> headlight burnt out, etc etc. Since each of these stats can occur
> independently, just replacing one entire image for each combination of
> stats is crazy inefficient.

> I've been using a bit of code that layers a bitmap (with a transparent
> background) on top another. What I'm not sure about is how to modify
> the layered images. Let's say I have 5 smaller images layered on top
> of the large car image, is there a way I can change the bitmap of one
> of the layered images in real time and delete those I no longer wish
> to display?

> In the below code, I draw the "low_tire.png" image on top the
> "car.png". Then when the button is clicked I would like the
> "low_tire.png" to be changed with the "flat_tire.png" image. How would
> I accomplish this? And how would I delete the layered image
> completely?

> Here's my code thus far:

> [CODE]
> import wx

> class Frame1(wx.Frame):
> def __init__(self, prnt):
> wx.Frame.__init__(self, id=-1, name='', parent=prnt,
> pos=wx.Point(0, 0), size=wx.Size(600, 600),
> style=wx.DEFAULT_FRAME_STYLE, title='Frame1')
> self.panel1 = BmpPanel(self)
> self.Show()

> class BmpPanel(wx.Panel):
> def __init__(self, parent, id = -1):
> wx.Panel.__init__(self, parent, id)

> self.Bind(wx.EVT_PAINT, self.OnPaint)

> self.button = wx.Button(self, id, 'click to change layered
> image')
> self.Bind(wx.EVT_BUTTON, self.modTheImage,
> id=self.button.GetId())

> self.BackBmp = wx.Bitmap('car.png')
> self.FrontBmp = wx.Bitmap('low_tire.png')
> self.hiBmp = wx.Bitmap('door_ajar.png')

> def OnPaint(self, event):
> self.dc = wx.PaintDC(self)
> self.Update()

> def Update(self):
> self.dc.DrawBitmap(self.BackBmp, 96, 72, True)
> self.dc.DrawBitmap(self.FrontBmp, 150, 110, True)

> def modTheImage(self, event):
> self.FrontBmp = wx.Bitmap('flat_tire.png') # ATTEMPT TO CHANCE
> IMAGE FILE (DOES NOT WORK)
> #self.Update
> #self.Refresh() # USING THIS SEEMS TO CRASH THE APPLICATION

> App = wx.PySimpleApp()
> application = Frame1(None)
> application.Show()
> App.MainLoop()
> [/CODE]

> Thanks all!

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

Interesting thought Steve, I'll have to give that a try.

There's also something amiss with the code. When displaying two
images, one layered on top another, hovering over the images rapidly
leads to fairly minimal CPU usage, however if I switch to another
window and back, the images begin flickering madly and CPU usage maxes
out. Also, if I enable double buffering, hovering over the images
rapidly leads to around 30% CPU usage. I'm not sure what's going. I
don't have these problems with staticBitmaps and double buffering. It
seems that wx.EVT_PAINT is being called very frequently for some
reason. Is there a way to eliminate this?

···

On Dec 2, 11:44 pm, Steve Barnes <GadgetSt...@live.co.uk> wrote:

-----Original Message-----
From: Convoluted
Sent: Friday, December 03, 2010 6:27 AM
To: wxPython-users
Subject: [wxPython-users] Re: Trying to modify part of image by layering bitmaps

Whoops, just found a quick typo. Should be:

  def modTheImage\(self, event\):
      self\.dc\.Clear\(\)
      self\.FrontBmp = wx\.Bitmap\(&#39;flat\_tire\.png&#39;\)
      self\.Update\(\) \# Forgot the brackets\! :\)

which does indeed replace the image. Still looking for a way to delete
an image, and of course any suggestions if anyone has any!

Of course you could always replace the image with a completely transparent one, while this does not free up the resources it does mean that you are reserving the same resources all the time this should make things more responsive.

Gadget/Steve

On Dec 2, 10:06 pm, Convoluted <xenon...@gmail.com> wrote:
> Hope you kind folk can spare a bit of advice. I'm trying to find a
> clever way to modifying a part of an image without replacing the image
> completely. For instance, let's say I have an image of a car and I
> would like to show the tire is flat. Instead of replacing the image
> completely with another, I would like to layer a new image of a flat
> tire image on top of current tire image. Eventually I would like to
> extend this to show multiple stats of the car, flat tires, ajar doors,
> headlight burnt out, etc etc. Since each of these stats can occur
> independently, just replacing one entire image for each combination of
> stats is crazy inefficient.

> I've been using a bit of code that layers a bitmap (with a transparent
> background) on top another. What I'm not sure about is how to modify
> the layered images. Let's say I have 5 smaller images layered on top
> of the large car image, is there a way I can change the bitmap of one
> of the layered images in real time and delete those I no longer wish
> to display?

> In the below code, I draw the "low_tire.png" image on top the
> "car.png". Then when the button is clicked I would like the
> "low_tire.png" to be changed with the "flat_tire.png" image. How would
> I accomplish this? And how would I delete the layered image
> completely?

> Here's my code thus far:

> [CODE]
> import wx

> class Frame1(wx.Frame):
> def __init__(self, prnt):
> wx.Frame.__init__(self, id=-1, name='', parent=prnt,
> pos=wx.Point(0, 0), size=wx.Size(600, 600),
> style=wx.DEFAULT_FRAME_STYLE, title='Frame1')
> self.panel1 = BmpPanel(self)
> self.Show()

> class BmpPanel(wx.Panel):
> def __init__(self, parent, id = -1):
> wx.Panel.__init__(self, parent, id)

> self.Bind(wx.EVT_PAINT, self.OnPaint)

> self.button = wx.Button(self, id, 'click to change layered
> image')
> self.Bind(wx.EVT_BUTTON, self.modTheImage,
> id=self.button.GetId())

> self.BackBmp = wx.Bitmap('car.png')
> self.FrontBmp = wx.Bitmap('low_tire.png')
> self.hiBmp = wx.Bitmap('door_ajar.png')

> def OnPaint(self, event):
> self.dc = wx.PaintDC(self)
> self.Update()

> def Update(self):
> self.dc.DrawBitmap(self.BackBmp, 96, 72, True)
> self.dc.DrawBitmap(self.FrontBmp, 150, 110, True)

> def modTheImage(self, event):
> self.FrontBmp = wx.Bitmap('flat_tire.png') # ATTEMPT TO CHANCE
> IMAGE FILE (DOES NOT WORK)
> #self.Update
> #self.Refresh() # USING THIS SEEMS TO CRASH THE APPLICATION

> App = wx.PySimpleApp()
> application = Frame1(None)
> application.Show()
> App.MainLoop()
> [/CODE]

> Thanks all!

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

The classic way to do this, and the way I would probably do it, is to
do all of your drawing offscreen. Any time the image stack changes,
just redraw all of the component images into a separate composition
bitmap, then blit that composition bitmap to the screen. That way,
there's never any flicker. This is essentially how OpenGL
applications work.

You will probably want to use something like PIL to do the image
manipulation, but the extra CPU utilization would be minimal.

···

--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

On Dec 2, 10:06 pm, Convoluted <xenon...@gmail.com> wrote:

Hope you kind folk can spare a bit of advice. I'm trying to find a
clever way to modifying a part of an image without replacing the image
completely. For instance, let's say I have an image of a car and I
would like to show the tire is flat. Instead of replacing the image
completely with another, I would like to layer a new image of a flat
tire image on top of current tire image. Eventually I would like to
extend this to show multiple stats of the car, flat tires, ajar doors,
headlight burnt out, etc etc. Since each of these stats can occur
independently, just replacing one entire image for each combination of
stats is crazy inefficient.

Convoluted wrote:

window and back, the images begin flickering madly and CPU usage maxes
out. Also, if I enable double buffering, hovering over the images
rapidly leads to around 30% CPU usage. I'm not sure what's going.

I don't know if this is it, but you've overridden he wx.Window Update() method, which is what gets called when you want a window to repaint. I'd name that something else.

-Chris

  I

···

don't have these problems with staticBitmaps and double buffering. It
seems that wx.EVT_PAINT is being called very frequently for some
reason. Is there a way to eliminate this?

On Dec 2, 11:44 pm, Steve Barnes <GadgetSt...@live.co.uk> wrote:

  -----Original Message-----
  From: Convoluted
  Sent: Friday, December 03, 2010 6:27 AM
  To: wxPython-users
  Subject: [wxPython-users] Re: Trying to modify part of image by layering bitmaps

  Whoops, just found a quick typo. Should be:

      def modTheImage(self, event):
          self.dc.Clear()
          self.FrontBmp = wx.Bitmap('flat_tire.png')
          self.Update() # Forgot the brackets! :slight_smile:

  which does indeed replace the image. Still looking for a way to delete
  an image, and of course any suggestions if anyone has any!

Of course you could always replace the image with a completely transparent one, while this does not free up the resources it does mean that you are reserving the same resources all the time this should make things more responsive.

Gadget/Steve

  On Dec 2, 10:06 pm, Convoluted <xenon...@gmail.com> wrote:
  > Hope you kind folk can spare a bit of advice. I'm trying to find a
  > clever way to modifying a part of an image without replacing the image
  > completely. For instance, let's say I have an image of a car and I
  > would like to show the tire is flat. Instead of replacing the image
  > completely with another, I would like to layer a new image of a flat
  > tire image on top of current tire image. Eventually I would like to
  > extend this to show multiple stats of the car, flat tires, ajar doors,
  > headlight burnt out, etc etc. Since each of these stats can occur
  > independently, just replacing one entire image for each combination of
  > stats is crazy inefficient.

  > I've been using a bit of code that layers a bitmap (with a transparent
  > background) on top another. What I'm not sure about is how to modify
  > the layered images. Let's say I have 5 smaller images layered on top
  > of the large car image, is there a way I can change the bitmap of one
  > of the layered images in real time and delete those I no longer wish
  > to display?

  > In the below code, I draw the "low_tire.png" image on top the
  > "car.png". Then when the button is clicked I would like the
  > "low_tire.png" to be changed with the "flat_tire.png" image. How would
  > I accomplish this? And how would I delete the layered image
  > completely?

  > Here's my code thus far:

  > [CODE]
  > import wx

  > class Frame1(wx.Frame):
  > def __init__(self, prnt):
  > wx.Frame.__init__(self, id=-1, name='', parent=prnt,
  > pos=wx.Point(0, 0), size=wx.Size(600, 600),
  > style=wx.DEFAULT_FRAME_STYLE, title='Frame1')
  > self.panel1 = BmpPanel(self)
  > self.Show()

  > class BmpPanel(wx.Panel):
  > def __init__(self, parent, id = -1):
  > wx.Panel.__init__(self, parent, id)

  > self.Bind(wx.EVT_PAINT, self.OnPaint)

  > self.button = wx.Button(self, id, 'click to change layered
  > image')
  > self.Bind(wx.EVT_BUTTON, self.modTheImage,
  > id=self.button.GetId())

  > self.BackBmp = wx.Bitmap('car.png')
  > self.FrontBmp = wx.Bitmap('low_tire.png')
  > self.hiBmp = wx.Bitmap('door_ajar.png')

  > def OnPaint(self, event):
  > self.dc = wx.PaintDC(self)
  > self.Update()

  > def Update(self):
  > self.dc.DrawBitmap(self.BackBmp, 96, 72, True)
  > self.dc.DrawBitmap(self.FrontBmp, 150, 110, True)

  > def modTheImage(self, event):
  > self.FrontBmp = wx.Bitmap('flat_tire.png') # ATTEMPT TO CHANCE
  > IMAGE FILE (DOES NOT WORK)
  > #self.Update
  > #self.Refresh() # USING THIS SEEMS TO CRASH THE APPLICATION

  > App = wx.PySimpleApp()
  > application = Frame1(None)
  > application.Show()
  > App.MainLoop()
  > [/CODE]

  > Thanks all!

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

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

[[ This group prefers bottom-posting. See Top Posting and Bottom Posting and Why is Bottom-posting better than Top-posting ]]

If you are on Windows and do not create a wx.PaintDC then that is your problem. If there is no wx.PaintDC created then when control returns to the system it sees that the window is still marked dirty (needing a refresh) and so it sends another paint event immediately.

···

On 12/3/10 12:16 AM, Convoluted wrote:

Interesting thought Steve, I'll have to give that a try.

There's also something amiss with the code. When displaying two
images, one layered on top another, hovering over the images rapidly
leads to fairly minimal CPU usage, however if I switch to another
window and back, the images begin flickering madly and CPU usage maxes
out. Also, if I enable double buffering, hovering over the images
rapidly leads to around 30% CPU usage. I'm not sure what's going. I
don't have these problems with staticBitmaps and double buffering. It
seems that wx.EVT_PAINT is being called very frequently for some
reason. Is there a way to eliminate this?

--
Robin Dunn
Software Craftsman

Thanks for the suggestions everyone. I have found the source of the
problem. I was using self.dc = wx.PaintDC(self) instead of dc =
wx.PaintDC(self). Robin, I believe this related to what you are
saying, where the wx.PaintDC is not actually created in the handler
and instead on the parent panel (I think?).

So going back to the concept of replacing an image. So let's say my
onPaint method looks like the following:

    def OnPaint(self, evt):
        dc = wx.PaintDC(self)
        dc.Clear()
        dc.DrawBitmap(self.photo1, 0, 0, True)
        dc.DrawBitmap(self.photo2, 0, 0, True)

Then let's say I have a simple button and I bind a button event that
calls a function to replace the self.photo1 with another image.
Something like this:

        self.button = wx.Button(self, -1, 'switch', pos=(0, 0))
        self.Bind(wx.EVT_BUTTON, self.goSwitch,
id=self.button.GetId())

How would I go about modifying the contents then refreshing the
display to observe the new change? I was thinking about something
like:

    def goSwitch(self, event):
        self.img = wx.Image("anotherimage.png")
        self.photo1 = self.img.ConvertToBitmap()

But the new image is not replaced since wx.EVT_PAINT is not invoked
and onPaint() is not called. And I can't call
dc.DrawBitmap(self.photo2, 0, 0, True) since it's only available in
the onPaint() method. Any ideas how I can accomplish this? Thanks
again

···

On Dec 3, 11:30 am, Robin Dunn <ro...@alldunn.com> wrote:

On 12/3/10 12:16 AM, Convoluted wrote:

> Interesting thought Steve, I'll have to give that a try.

> There's also something amiss with the code. When displaying two
> images, one layered on top another, hovering over the images rapidly
> leads to fairly minimal CPU usage, however if I switch to another
> window and back, the images begin flickering madly and CPU usage maxes
> out. Also, if I enable double buffering, hovering over the images
> rapidly leads to around 30% CPU usage. I'm not sure what's going. I
> don't have these problems with staticBitmaps and double buffering. It
> seems that wx.EVT_PAINT is being called very frequently for some
> reason. Is there a way to eliminate this?

[[ This group prefers bottom-posting. Seehttp://idallen.com/topposting.htmlandhttp://www.caliburn.nl/topposting.html]]

If you are on Windows and do not create a wx.PaintDC then that is your
problem. If there is no wx.PaintDC created then when control returns to
the system it sees that the window is still marked dirty (needing a
refresh) and so it sends another paint event immediately.

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

Hmmm, okay here's my attempt at solving this issue (sorry I'm using
this thread as a personal notepad, but I hope this will help someone
with similar problems). I call doDrawing() when I need something
drawn, and I modify the contents of self.photo1 with the image I would
like to change to. How does this look to everyone? I'm just beginning
to learn to use DC, so I may have missed something import, but it
seems to work for this basic example. I can post the full code if
someone is interested.

    def goSwitch(self, event):
        self.img = wx.Image("level0.png")
        self.photo1 = self.img.ConvertToBitmap()
        self.doDrawing()

    def OnPaint(self, evt):
        dc = wx.PaintDC(self)
        brush = wx.Brush("#444444")
        dc.SetBackground(brush)
        dc.Clear()
        self.doDrawing()

    def doDrawing(self):
        dc = wx.ClientDC(self)
        dc.DrawBitmap(self.photo1, 0, 0, True)
        dc.DrawBitmap(self.photo2, 0, 0, True)

···

On Dec 3, 1:01 pm, Convoluted <xenon...@gmail.com> wrote:

Thanks for the suggestions everyone. I have found the source of the
problem. I was using self.dc = wx.PaintDC(self) instead of dc =
wx.PaintDC(self). Robin, I believe this related to what you are
saying, where the wx.PaintDC is not actually created in the handler
and instead on the parent panel (I think?).

So going back to the concept of replacing an image. So let's say my
onPaint method looks like the following:

def OnPaint\(self, evt\):
    dc = wx\.PaintDC\(self\)
    dc\.Clear\(\)
    dc\.DrawBitmap\(self\.photo1, 0, 0, True\)
    dc\.DrawBitmap\(self\.photo2, 0, 0, True\)

Then let's say I have a simple button and I bind a button event that
calls a function to replace the self.photo1 with another image.
Something like this:

    self\.button = wx\.Button\(self, \-1, &#39;switch&#39;, pos=\(0, 0\)\)
    self\.Bind\(wx\.EVT\_BUTTON, self\.goSwitch,

id=self.button.GetId())

How would I go about modifying the contents then refreshing the
display to observe the new change? I was thinking about something
like:

def goSwitch\(self, event\):
    self\.img = wx\.Image\(&quot;anotherimage\.png&quot;\)
    self\.photo1 = self\.img\.ConvertToBitmap\(\)

But the new image is not replaced since wx.EVT_PAINT is not invoked
and onPaint() is not called. And I can't call
dc.DrawBitmap(self.photo2, 0, 0, True) since it's only available in
the onPaint() method. Any ideas how I can accomplish this? Thanks
again

On Dec 3, 11:30 am, Robin Dunn <ro...@alldunn.com> wrote:

> On 12/3/10 12:16 AM, Convoluted wrote:

> > Interesting thought Steve, I'll have to give that a try.

> > There's also something amiss with the code. When displaying two
> > images, one layered on top another, hovering over the images rapidly
> > leads to fairly minimal CPU usage, however if I switch to another
> > window and back, the images begin flickering madly and CPU usage maxes
> > out. Also, if I enable double buffering, hovering over the images
> > rapidly leads to around 30% CPU usage. I'm not sure what's going. I
> > don't have these problems with staticBitmaps and double buffering. It
> > seems that wx.EVT_PAINT is being called very frequently for some
> > reason. Is there a way to eliminate this?

> [[ This group prefers bottom-posting. Seehttp://idallen.com/topposting.htmlandhttp://www.caliburn.nl/toppostin…]]

> If you are on Windows and do not create a wx.PaintDC then that is your
> problem. If there is no wx.PaintDC created then when control returns to
> the system it sees that the window is still marked dirty (needing a
> refresh) and so it sends another paint event immediately.

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

Thanks for the suggestions everyone.

Take a look at the wiki on "images and drawing", and various ones on DCs (the double buffering one could be helpful) that will help you understand all this. But for the moment:

I have found the source of the
problem. I was using self.dc = wx.PaintDC(self) instead of dc =
wx.PaintDC(self).

yup -- as a rule, you don't want to keep DCs around -- and in particular, not a paintDC -- it needs to be recreated each time.

So going back to the concept of replacing an image. So let's say my
onPaint method looks like the following:

     def OnPaint(self, evt):
         dc = wx.PaintDC(self)
         dc.Clear()
         dc.DrawBitmap(self.photo1, 0, 0, True)
         dc.DrawBitmap(self.photo2, 0, 0, True)

Then let's say I have a simple button and I bind a button event that
calls a function to replace the self.photo1 with another image.
Something like this:

         self.button = wx.Button(self, -1, 'switch', pos=(0, 0))
         self.Bind(wx.EVT_BUTTON, self.goSwitch,
id=self.button.GetId())

just a note here -- it's a little cleaner to write that
    self.button.Bind(wx.EVT_BUTTON, self.goSwitch)

How would I go about modifying the contents then refreshing the
display to observe the new change? I was thinking about something
like:

     def goSwitch(self, event):
         self.img = wx.Image("anotherimage.png")
         self.photo1 = self.img.ConvertToBitmap()

But the new image is not replaced since wx.EVT_PAINT is not invoked
and onPaint() is not called. And I can't call
dc.DrawBitmap(self.photo2, 0, 0, True) since it's only available in
the onPaint() method. Any ideas how I can accomplish this? Thanks
again

Two options:

The modern "preferred" way to call:

self.Refresh()
self.Update()

at the end of goSwitch. That will trigger a paint event, which will call your handler.

If that isn't responsive enough, you can create a wx.ClientDC, and call its DrawBitmap() method.

-Chris

···

On 12/3/10 1:01 PM, Convoluted wrote:

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

How does this look to everyone?

     def goSwitch(self, event):
         self.img = wx.Image("level0.png")
         self.photo1 = self.img.ConvertToBitmap()
         self.doDrawing()

     def OnPaint(self, evt):
         dc = wx.PaintDC(self)
         brush = wx.Brush("#444444")
         dc.SetBackground(brush)
         dc.Clear()
         self.doDrawing()

     def doDrawing(self):
         dc = wx.ClientDC(self)
         dc.DrawBitmap(self.photo1, 0, 0, True)
         dc.DrawBitmap(self.photo2, 0, 0, True)

not quite. Ideally, you do all your drawing on the OnPaint, and use Update() to trigger that when you need to.

However, I've found that isn't always totally responsive, so a ClientDC can be useful. In which case, you want to put your drawing code in a method that takes a dc as a parameter, then call it with the appropriate DC (untested):

       def goSwitch(self, event):
           self.img = wx.Image("level0.png")
           self.photo1 = self.img.ConvertToBitmap()
           dc = wx.ClientDC(self)
           self.doDrawing(dc)

       def OnPaint(self, evt):
           dc = wx.PaintDC(self)
           self.doDrawing(dc)

       def doDrawing(self, dc):
           brush = wx.Brush("#444444")
           dc.SetBackground(brush)
           dc.Clear()
           dc.DrawBitmap(self.photo1, 0, 0, True)
           dc.DrawBitmap(self.photo2, 0, 0, True)

> I can post the full code if
> someone is interested.

always a good idea:

http://wiki.wxpython.org/MakingSampleApps

···

On 12/3/10 1:21 PM, Convoluted wrote:

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

That is not ideal either, since you end up using both the PaintDC and the ClientDC in the OnPaint code path. An easy change to avoid this is make it so you can pass the dc to doDrawing and have it create the ClientDC only if it needs to.

A better fix would be to not use the ClientDC at all and use a double buffering technique instead. There are lots of examples of this on the wiki and elsewhere, but in a nutshell you:

1. maintain a wx.Bitmap that is the same size as your window's client area (you can bind the EVT_SIZE event and create and initialize a new bitmap with the new size)

2. Have a method that initializes the bitmap with whatever background content you want it to have, using a wx.MemoryDC or a wx.BufferedDC

3. whenever you need to change the content of what is displayed in the window you can first update that bitmap (again with a memory or buffered DC) and then call Refresh.

4. In the EVT_PAINT handler all you need to do is draw that bitmap to the window and nothing else since the bitmap already has all of the content drawn in it. Since there is no clearing step and there is only 1 drawing step, then flicker is eliminated.

···

On 12/3/10 1:21 PM, Convoluted wrote:

Hmmm, okay here's my attempt at solving this issue (sorry I'm using
this thread as a personal notepad, but I hope this will help someone
with similar problems). I call doDrawing() when I need something
drawn, and I modify the contents of self.photo1 with the image I would
like to change to. How does this look to everyone? I'm just beginning
to learn to use DC, so I may have missed something import, but it
seems to work for this basic example. I can post the full code if
someone is interested.

     def goSwitch(self, event):
         self.img = wx.Image("level0.png")
         self.photo1 = self.img.ConvertToBitmap()
         self.doDrawing()

     def OnPaint(self, evt):
         dc = wx.PaintDC(self)
         brush = wx.Brush("#444444")
         dc.SetBackground(brush)
         dc.Clear()
         self.doDrawing()

     def doDrawing(self):
         dc = wx.ClientDC(self)
         dc.DrawBitmap(self.photo1, 0, 0, True)
         dc.DrawBitmap(self.photo2, 0, 0, True)

--
Robin Dunn
Software Craftsman

Christopher, thanks for the code snippet, much appreciated. I've
incorporated into the program. Robin, double buffering is a great
indeed. On Windows, I actually found code that seems to double buffer
everything without using wx.BufferedDC or any other well documented
technique. Works with bitmap buttons, statictext, video capture,
absolutely everything. Work like magic (I say this because I haven't
read up on what it actually does, so it is actually like magic to me).
I usually just toss it where I define wx.Frame. Anyone know the cons
of using this technique?

        import win32api
        import win32con

        def SetCompositeMode(self, on=True):
            exstyle = win32api.GetWindowLong(self.GetHandle(),
win32con.GWL_EXSTYLE)
            if on: exstyle |= win32con.WS_EX_COMPOSITED
            else: exstyle &= ~win32con.WS_EX_COMPOSITED
            win32api.SetWindowLong(self.GetHandle(),
win32con.GWL_EXSTYLE, exstyle)

        SetCompositeMode(self, True)

Here is my updated code so far. So far works like a charm. Like I
mentioned previously if I would like to delete a layered image, I
change the image to a transparent graphic so the graphic underneath
shows through. Probably not the best technique, but it works just
fine. Perhaps a better option would be to pass an argument into the
drawing function which turns on or off the dc.DrawBitmap methods. I
suspect it would be more efficient than constantly drawing a bunch of
transparent graphics.

I decided to include a button that toggles between two graphic states,
to test how quickly I could switch between layering graphics. I'm
using a global variable to keep track of the button state. Any
suggestions that wold be a better choice than a global variable?

Thanks again for all the help.

···

####
import wx
import win32api
import win32con

# Variables to keep track of state of button toggle
global switchFrontWheel
switchFrontWheel = True

class RandomImagePlacementWindow(wx.Panel):
    def __init__(self, parent):
        wx.Panel.__init__(self, parent)

        # Create some simple buttons
        self.button1 = wx.Button(self, -1, 'Front wheel', pos=(10,
10))
        self.button2 = wx.Button(self, -1, 'Rear wheel', pos=(10, 30))
        self.button3 = wx.Button(self, -1, 'Front door', pos=(10, 50))
        self.button4 = wx.Button(self, -1, 'Rear door', pos=(10, 70))

        # Bind events
        self.Bind(wx.EVT_BUTTON, self.goFrontWheel,
id=self.button1.GetId())
        self.Bind(wx.EVT_BUTTON, self.goRearWheel,
id=self.button2.GetId())
        self.Bind(wx.EVT_BUTTON, self.goFrontDoor,
id=self.button3.GetId())
        self.Bind(wx.EVT_BUTTON, self.goRearDoor,
id=self.button4.GetId())
        self.Bind(wx.EVT_PAINT, self.OnPaint)

        # Initialize background image and transparent layer
        self.carFrame = wx.Bitmap("carSideFrame.png")
        self.transReset = wx.Bitmap("carSideTransparent.png")

        # Initialize transparent layers
        self.transFrontWheel = wx.Bitmap("carSideTransparent.png")
        self.transRearWheel = wx.Bitmap("carSideTransparent.png")
        self.transFrontDoor = wx.Bitmap("carSideTransparent.png")
        self.transRearDoor = wx.Bitmap("carSideTransparent.png")

        # Initialize active (highlighted) layers
        self.frontWheel = wx.Bitmap("carSideFrontWheel.png")
        self.rearWheel = wx.Bitmap("carSideRearWheel.png")
        self.frontDoor = wx.Bitmap("carSideFrontDoor.png")
        self.rearDoor = wx.Bitmap("carSideRearDoor.png")

    # Toggle between background wheel
    # (transparent layer) and highlihted wheel
    def goFrontWheel(self, event):
        global switchFrontWheel
        if switchFrontWheel == True:
            switchFrontWheel = False
            self.transFrontWheel = self.frontWheel
            dc = wx.ClientDC(self)
            self.doDrawing(dc)
        else:
            switchFrontWheel = True
            self.transFrontWheel = self.transReset
            dc = wx.ClientDC(self)
            self.doDrawing(dc)

    # Change from background wheel (transparent
    # layer) to highlihted wheel
    def goRearWheel(self, event):
        self.transRearWheel = self.rearWheel
        dc = wx.ClientDC(self)
        self.doDrawing(dc)

    def goFrontDoor(self, event):
        self.transFrontDoor = self.frontDoor
        dc = wx.ClientDC(self)
        self.doDrawing(dc)

    def goRearDoor(self, event):
        self.transRearDoor = self.rearDoor
        dc = wx.ClientDC(self)
        self.doDrawing(dc)

    def OnPaint(self, evt):
        dc = wx.PaintDC(self)
        dc = wx.ClientDC(self)
        self.doDrawing(dc)

    def doDrawing(self, dc):
        brush = wx.Brush("#444444")
        dc.SetBackground(brush)
        dc.Clear()
        dc.DrawBitmap(self.carFrame, 100, 0, True)
        dc.DrawBitmap(self.transFrontWheel, 100, 0, True)
        dc.DrawBitmap(self.transRearWheel, 100, 0, True)
        dc.DrawBitmap(self.transFrontDoor, 100, 0, True)
        dc.DrawBitmap(self.transRearDoor, 100, 0, True)

class TestFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, title="Loading Images",
size=(640,250))
        win = RandomImagePlacementWindow(self)

        # used only in Windows, remove if on other platforms
        def SetCompositeMode(self, on=True):
            exstyle = win32api.GetWindowLong(self.GetHandle(),
win32con.GWL_EXSTYLE)
            if on: exstyle |= win32con.WS_EX_COMPOSITED
            else: exstyle &= ~win32con.WS_EX_COMPOSITED
            win32api.SetWindowLong(self.GetHandle(),
win32con.GWL_EXSTYLE, exstyle)
        SetCompositeMode(self, True)

app = wx.PySimpleApp()
frm = TestFrame()
frm.Show()
app.MainLoop()

On Dec 3, 1:55 pm, Robin Dunn <ro...@alldunn.com> wrote:

On 12/3/10 1:21 PM, Convoluted wrote:

> Hmmm, okay here's my attempt at solving this issue (sorry I'm using
> this thread as a personal notepad, but I hope this will help someone
> with similar problems). I call doDrawing() when I need something
> drawn, and I modify the contents of self.photo1 with the image I would
> like to change to. How does this look to everyone? I'm just beginning
> to learn to use DC, so I may have missed something import, but it
> seems to work for this basic example. I can post the full code if
> someone is interested.

> def goSwitch(self, event):
> self.img = wx.Image("level0.png")
> self.photo1 = self.img.ConvertToBitmap()
> self.doDrawing()

> def OnPaint(self, evt):
> dc = wx.PaintDC(self)
> brush = wx.Brush("#444444")
> dc.SetBackground(brush)
> dc.Clear()
> self.doDrawing()

> def doDrawing(self):
> dc = wx.ClientDC(self)
> dc.DrawBitmap(self.photo1, 0, 0, True)
> dc.DrawBitmap(self.photo2, 0, 0, True)

That is not ideal either, since you end up using both the PaintDC and
the ClientDC in the OnPaint code path. An easy change to avoid this is
make it so you can pass the dc to doDrawing and have it create the
ClientDC only if it needs to.

A better fix would be to not use the ClientDC at all and use a double
buffering technique instead. There are lots of examples of this on the
wiki and elsewhere, but in a nutshell you:

1. maintain a wx.Bitmap that is the same size as your window's client
area (you can bind the EVT_SIZE event and create and initialize a new
bitmap with the new size)

2. Have a method that initializes the bitmap with whatever background
content you want it to have, using a wx.MemoryDC or a wx.BufferedDC

3. whenever you need to change the content of what is displayed in the
window you can first update that bitmap (again with a memory or buffered
DC) and then call Refresh.

4. In the EVT_PAINT handler all you need to do is draw that bitmap to
the window and nothing else since the bitmap already has all of the
content drawn in it. Since there is no clearing step and there is only
1 drawing step, then flicker is eliminated.

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

Christopher, thanks for the code snippet, much appreciated. I've
incorporated into the program. Robin, double buffering is a great
indeed. On Windows, I actually found code that seems to double buffer
everything without using wx.BufferedDC or any other well documented
technique. Works with bitmap buttons, statictext, video capture,
absolutely everything. Work like magic (I say this because I haven't
read up on what it actually does, so it is actually like magic to me).
I usually just toss it where I define wx.Frame. Anyone know the cons
of using this technique?

I've sometimes seen problems with it on XP, (refresh glitches, visual performance issues, and a few cases where it seems to not do anything at all) but on Vista and Win7 it should be much better.

         import win32api
         import win32con

         def SetCompositeMode(self, on=True):
             exstyle = win32api.GetWindowLong(self.GetHandle(),
win32con.GWL_EXSTYLE)
             if on: exstyle |= win32con.WS_EX_COMPOSITED
             else: exstyle&= ~win32con.WS_EX_COMPOSITED
             win32api.SetWindowLong(self.GetHandle(),
win32con.GWL_EXSTYLE, exstyle)

         SetCompositeMode(self, True)

You can do the same thing in wx with:

  theFrame.SetDoubleBuffered(True)

And you can use this to test if a window is in double buffered mode (so you can do double buffering yourself if desired and the system can't support it):

  theFrame.IsDoubleBuffered()

···

On 12/3/10 4:43 PM, Convoluted wrote:

--
Robin Dunn
Software Craftsman