4
This module contains the DoodleWindow class which is a window that you
5
can do simple drawings upon.
9
import wx # This module uses the new wx namespace
11
#----------------------------------------------------------------------
13
class DoodleWindow(wx.Window):
14
menuColours = { 100 : 'Black',
34
def __init__(self, parent, ID):
35
wx.Window.__init__(self, parent, ID, style=wx.NO_FULL_REPAINT_ON_RESIZE)
36
self.SetBackgroundColour("WHITE")
39
self.SetColour("Black")
41
self.pos = wx.Point(0,0)
46
self.SetCursor(wx.StockCursor(wx.CURSOR_PENCIL))
48
# hook some mouse events
49
self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
50
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
51
self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp)
52
self.Bind(wx.EVT_MOTION, self.OnMotion)
54
# the window resize event and idle events for managing the buffer
55
self.Bind(wx.EVT_SIZE, self.OnSize)
56
self.Bind(wx.EVT_IDLE, self.OnIdle)
58
# and the refresh event
59
self.Bind(wx.EVT_PAINT, self.OnPaint)
61
# When the window is destroyed, clean up resources.
62
self.Bind(wx.EVT_WINDOW_DESTROY, self.Cleanup)
65
def Cleanup(self, evt):
66
if hasattr(self, "menu"):
72
"""Initialize the bitmap used for buffering the display."""
73
size = self.GetClientSize()
74
self.buffer = wx.EmptyBitmap(max(1,size.width), max(1,size.height))
75
dc = wx.BufferedDC(None, self.buffer)
76
dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
79
self.reInitBuffer = False
82
def SetColour(self, colour):
83
"""Set a new colour and make a matching pen"""
85
self.pen = wx.Pen(self.colour, self.thickness, wx.SOLID)
89
def SetThickness(self, num):
90
"""Set a new line thickness and make a matching pen"""
92
self.pen = wx.Pen(self.colour, self.thickness, wx.SOLID)
96
def GetLinesData(self):
100
def SetLinesData(self, lines):
101
self.lines = lines[:]
107
"""Make a menu that can be popped up later"""
109
keys = self.menuColours.keys()
112
text = self.menuColours[k]
113
menu.Append(k, text, kind=wx.ITEM_CHECK)
114
self.Bind(wx.EVT_MENU_RANGE, self.OnMenuSetColour, id=100, id2=200)
115
self.Bind(wx.EVT_UPDATE_UI_RANGE, self.OnCheckMenuColours, id=100, id2=200)
118
for x in range(1, self.maxThickness+1):
119
menu.Append(x, str(x), kind=wx.ITEM_CHECK)
121
self.Bind(wx.EVT_MENU_RANGE, self.OnMenuSetThickness, id=1, id2=self.maxThickness)
122
self.Bind(wx.EVT_UPDATE_UI_RANGE, self.OnCheckMenuThickness, id=1, id2=self.maxThickness)
126
# These two event handlers are called before the menu is displayed
127
# to determine which items should be checked.
128
def OnCheckMenuColours(self, event):
129
text = self.menuColours[event.GetId()]
130
if text == self.colour:
132
event.SetText(text.upper())
137
def OnCheckMenuThickness(self, event):
138
if event.GetId() == self.thickness:
144
def OnLeftDown(self, event):
145
"""called when the left mouse button is pressed"""
147
self.pos = event.GetPosition()
151
def OnLeftUp(self, event):
152
"""called when the left mouse button is released"""
153
if self.HasCapture():
154
self.lines.append( (self.colour, self.thickness, self.curLine) )
159
def OnRightUp(self, event):
160
"""called when the right mouse button is released, will popup the menu"""
161
pt = event.GetPosition()
162
self.PopupMenu(self.menu, pt)
166
def OnMotion(self, event):
168
Called when the mouse is in motion. If the left button is
169
dragging then draw a line from the last event position to the
170
current one. Save the coordinants for redraws.
172
if event.Dragging() and event.LeftIsDown():
173
dc = wx.BufferedDC(wx.ClientDC(self), self.buffer)
176
pos = event.GetPosition()
177
coords = (self.pos.x, self.pos.y, pos.x, pos.y)
178
self.curLine.append(coords)
184
def OnSize(self, event):
186
Called when the window is resized. We set a flag so the idle
187
handler will resize the buffer.
189
self.reInitBuffer = True
192
def OnIdle(self, event):
194
If the size was changed then resize the bitmap used for double
195
buffering to match the window size. We do it in Idle time so
196
there is only one refresh after resizing is done, not lots while
199
if self.reInitBuffer:
204
def OnPaint(self, event):
206
Called when the window is exposed.
208
# Create a buffered paint DC. It will create the real
209
# wx.PaintDC and then blit the bitmap to it when dc is
210
# deleted. Since we don't need to draw anything else
211
# here that's all there is to it.
212
dc = wx.BufferedPaintDC(self, self.buffer)
215
def DrawLines(self, dc):
217
Redraws all the lines that have been drawn already.
220
for colour, thickness, line in self.lines:
221
pen = wx.Pen(colour, thickness, wx.SOLID)
228
# Event handlers for the popup menu, uses the event ID to determine
229
# the colour or the thickness to set.
230
def OnMenuSetColour(self, event):
231
self.SetColour(self.menuColours[event.GetId()])
233
def OnMenuSetThickness(self, event):
234
self.SetThickness(event.GetId())
237
# Observer pattern. Listeners are registered and then notified
238
# whenever doodle settings change.
239
def AddListener(self, listener):
240
self.listeners.append(listener)
243
for other in self.listeners:
244
other.Update(self.colour, self.thickness)
247
#----------------------------------------------------------------------
249
class DoodleFrame(wx.Frame):
250
def __init__(self, parent):
251
wx.Frame.__init__(self, parent, -1, "Doodle Frame", size=(800,600),
252
style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE)
253
doodle = DoodleWindow(self, -1)
255
#----------------------------------------------------------------------
257
if __name__ == '__main__':
258
app = wx.PySimpleApp()
259
frame = DoodleFrame(None)