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?
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.
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