Introduction
This page contains the current version of the BufferedCanvas widget class.
BufferedCanvas is a fairly simple widget that implements double-buffering and also removes flicker from the rendering. This means you can spend less time trying to find out what the hell a wx.BufferedPaintDC is, and more time writing drawing code.
bufferedcanvas.py
1 """
2 BufferedCanvas -- Double-buffered, flicker-free canvas widget
3 Copyright (C) 2005, 2006 Daniel Keep
4
5 To use this widget, just override or replace the draw method.
6 This will be called whenever the widget size changes, or when
7 the update method is explicitly called.
8
9 Please submit any improvements/bugfixes/ideas to the following
10 url:
11
12 http://wiki.wxpython.org/index.cgi/BufferedCanvas
13
14 2006-04-29: Added bugfix for a crash on Mac provided by Marc Jans.
15 """
16
17 # Hint: try removing '.sp4msux0rz'
18 __author__ = 'Daniel Keep <daniel.keep.sp4msux0rz@gmail.com>'
19
20 __license__ = """
21 This library is free software; you can redistribute it and/or
22 modify it under the terms of the GNU Lesser General Public License as
23 published by the Free Software Foundation; either version 2.1 of the
24 License, or (at your option) any later version.
25
26 As a special exception, the copyright holders of this library
27 hereby recind Section 3 of the GNU Lesser General Public License. This
28 means that you MAY NOT apply the terms of the ordinary GNU General
29 Public License instead of this License to any given copy of the
30 Library. This has been done to prevent users of the Library from being
31 denied access or the ability to use future improvements.
32
33 This library is distributed in the hope that it will be useful, but
34 WITHOUT ANY WARRANTY; without even the implied warranty of
35 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
36 General Public License for more details.
37
38 You should have received a copy of the GNU Lesser General Public
39 License along with this library; if not, write to the Free Software
40 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
41 """
42
43 __all__ = ['BufferedCanvas']
44
45 import wx
46
47 class BufferedCanvas(wx.Panel):
48 """
49 Implements a double-buffered, flicker-free canvas widget.
50
51 Standard usage is to subclass this class, and override the
52 draw method. The draw method is passed a device context, which
53 should be used to do your drawing.
54
55 Also, you should NOT call dc.BeginDrawing() and dc.EndDrawing() --
56 these methods are automatically called for you, although you still
57 need to manually clear the device context.
58
59 If you want to force a redraw (for whatever reason), you should
60 call the update method. This is because the draw method is never
61 called as a result of an EVT_PAINT event.
62 """
63
64 # These are our two buffers. Just be aware that when the buffers
65 # are flipped, the REFERENCES are swapped. So I wouldn't want to
66 # try holding onto explicit references to one or the other ;)
67 buffer = None
68 backbuffer = None
69
70 def __init__(self,
71 parent,
72 ID=-1,
73 pos=wx.DefaultPosition,
74 size=wx.DefaultSize,
75 style=wx.NO_FULL_REPAINT_ON_RESIZE):
76 wx.Panel.__init__(self,parent,ID,pos,size,style)
77
78 # Bind events
79 self.Bind(wx.EVT_PAINT, self.onPaint)
80 self.Bind(wx.EVT_SIZE, self.onSize)
81
82 # Disable background erasing (flicker-licious)
83 def disable_event(*pargs,**kwargs):
84 pass # the sauce, please
85 self.Bind(wx.EVT_ERASE_BACKGROUND, disable_event)
86
87 # Ensure that the buffers are setup correctly
88 self.onSize(None)
89
90 ##
91 ## General methods
92 ##
93
94 def draw(self,dc):
95 """
96 Stub: called when the canvas needs to be re-drawn.
97 """
98 pass
99
100
101 def flip(self):
102 """
103 Flips the front and back buffers.
104 """
105 self.buffer,self.backbuffer = self.backbuffer,self.buffer
106 self.Refresh()
107
108
109 def update(self):
110 """
111 Causes the canvas to be updated.
112 """
113 dc = wx.MemoryDC()
114 dc.SelectObject(self.backbuffer)
115 dc.BeginDrawing()
116 self.draw(dc)
117 dc.EndDrawing()
118 self.flip()
119
120 ##
121 ## Event handlers
122 ##
123
124 def onPaint(self, event):
125 # Blit the front buffer to the screen
126 dc = wx.BufferedPaintDC(self, self.buffer)
127
128
129 def onSize(self, event):
130 # Here we need to create a new off-screen buffer to hold
131 # the in-progress drawings on.
132 width,height = self.GetClientSizeTuple()
133 if width == 0:
134 width = 1
135 if height == 0:
136 height = 1
137 self.buffer = wx.EmptyBitmap(width,height)
138 self.backbuffer = wx.EmptyBitmap(width,height)
139
140 # Now update the screen
141 self.update()
Example
import wx from bufferedcanvas import * class TestCanvas(BufferedCanvas): def __init__(self,parent,ID=-1): BufferedCanvas.__init__(self,parent,ID) def draw(self, dc): dc.SetBackground(wx.Brush("Black")) dc.Clear() dc.SetBrush(wx.BLUE_BRUSH) dc.SetPen(wx.Pen('Red', 4)) dc.DrawRectangle(20,20,300,200) class TestFrame(wx.Frame): def __init__(self, parent=None, ID=-1, title="BufferedCanvas Test", pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE): wx.Frame.__init__(self,parent,ID,title,pos,size,style) self.canvas = TestCanvas(self) self.Bind(wx.EVT_CLOSE, self.onClose) def onClose(self,event): self.Show(False) self.Destroy() def main(): app = wx.PySimpleApp() frame = TestFrame() frame.Show(True) app.MainLoop() if __name__ == '__main__': main()
Comments
If you have any suggestions, improvements, or bug-fixes (there are bugs?!), then please let me know via my cunningly mangled email address (it's in the source code). Please don't go modifying the code without letting me know first.