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")
46 # hook some mouse events
47 wx
.EVT_LEFT_DOWN(self
, self
.OnLeftDown
)
48 wx
.EVT_LEFT_UP(self
, self
.OnLeftUp
)
49 wx
.EVT_RIGHT_UP(self
, self
.OnRightUp
)
50 wx
.EVT_MOTION(self
, self
.OnMotion
)
52 # the window resize event and idle events for managing the buffer
53 wx
.EVT_SIZE(self
, self
.OnSize
)
54 wx
.EVT_IDLE(self
, self
.OnIdle
)
56 # and the refresh event
57 wx
.EVT_PAINT(self
, self
.OnPaint
)
59 # When the window is destroyed, clean up resources.
60 wx
.EVT_WINDOW_DESTROY(self
, self
.Cleanup
)
63 def Cleanup(self
, evt
):
64 if hasattr(self
, "menu"):
70 """Initialize the bitmap used for buffering the display."""
71 size
= self
.GetClientSize()
72 self
.buffer = wx
.EmptyBitmap(size
.width
, size
.height
)
73 dc
= wx
.BufferedDC(None, self
.buffer)
74 dc
.SetBackground(wx
.Brush(self
.GetBackgroundColour()))
77 self
.reInitBuffer
= False
80 def SetColour(self
, colour
):
81 """Set a new colour and make a matching pen"""
83 self
.pen
= wx
.Pen(self
.colour
, self
.thickness
, wx
.SOLID
)
87 def SetThickness(self
, num
):
88 """Set a new line thickness and make a matching pen"""
90 self
.pen
= wx
.Pen(self
.colour
, self
.thickness
, wx
.SOLID
)
94 def GetLinesData(self
):
98 def SetLinesData(self
, lines
):
105 """Make a menu that can be popped up later"""
107 keys
= self
.menuColours
.keys()
110 text
= self
.menuColours
[k
]
111 menu
.Append(k
, text
, kind
=wx
.ITEM_CHECK
)
112 wx
.EVT_MENU_RANGE(self
, 100, 200, self
.OnMenuSetColour
)
113 wx
.EVT_UPDATE_UI_RANGE(self
, 100, 200, self
.OnCheckMenuColours
)
116 for x
in range(1, self
.maxThickness
+1):
117 menu
.Append(x
, str(x
), kind
=wx
.ITEM_CHECK
)
118 wx
.EVT_MENU_RANGE(self
, 1, self
.maxThickness
, self
.OnMenuSetThickness
)
119 wx
.EVT_UPDATE_UI_RANGE(self
, 1, self
.maxThickness
, self
.OnCheckMenuThickness
)
123 # These two event handlers are called before the menu is displayed
124 # to determine which items should be checked.
125 def OnCheckMenuColours(self
, event
):
126 text
= self
.menuColours
[event
.GetId()]
127 if text
== self
.colour
:
129 event
.SetText(text
.upper())
134 def OnCheckMenuThickness(self
, event
):
135 if event
.GetId() == self
.thickness
:
141 def OnLeftDown(self
, event
):
142 """called when the left mouse button is pressed"""
144 self
.x
, self
.y
= event
.GetPositionTuple()
148 def OnLeftUp(self
, event
):
149 """called when the left mouse button is released"""
150 if self
.HasCapture():
151 self
.lines
.append( (self
.colour
, self
.thickness
, self
.curLine
) )
156 def OnRightUp(self
, event
):
157 """called when the right mouse button is released, will popup the menu"""
158 pt
= event
.GetPosition()
159 self
.PopupMenu(self
.menu
, pt
)
163 def OnMotion(self
, event
):
165 Called when the mouse is in motion. If the left button is
166 dragging then draw a line from the last event position to the
167 current one. Save the coordinants for redraws.
169 if event
.Dragging() and event
.LeftIsDown():
170 dc
= wx
.BufferedDC(wx
.ClientDC(self
), self
.buffer)
173 pos
= event
.GetPositionTuple()
174 coords
= (self
.x
, self
.y
) + pos
175 self
.curLine
.append(coords
)
176 dc
.DrawLine(self
.x
, self
.y
, pos
[0], pos
[1])
181 def OnSize(self
, event
):
183 Called when the window is resized. We set a flag so the idle
184 handler will resize the buffer.
186 self
.reInitBuffer
= True
189 def OnIdle(self
, event
):
191 If the size was changed then resize the bitmap used for double
192 buffering to match the window size. We do it in Idle time so
193 there is only one refresh after resizing is done, not lots while
196 if self
.reInitBuffer
:
201 def OnPaint(self
, event
):
203 Called when the window is exposed.
205 # Create a buffered paint DC. It will create the real
206 # wx.PaintDC and then blit the bitmap to it when dc is
207 # deleted. Since we don't need to draw anything else
208 # here that's all there is to it.
209 dc
= wx
.BufferedPaintDC(self
, self
.buffer)
212 def DrawLines(self
, dc
):
214 Redraws all the lines that have been drawn already.
217 for colour
, thickness
, line
in self
.lines
:
218 pen
= wx
.Pen(colour
, thickness
, wx
.SOLID
)
221 apply(dc
.DrawLine
, coords
)
225 # Event handlers for the popup menu, uses the event ID to determine
226 # the colour or the thickness to set.
227 def OnMenuSetColour(self
, event
):
228 self
.SetColour(self
.menuColours
[event
.GetId()])
230 def OnMenuSetThickness(self
, event
):
231 self
.SetThickness(event
.GetId())
234 # Observer pattern. Listeners are registered and then notified
235 # whenever doodle settings change.
236 def AddListener(self
, listener
):
237 self
.listeners
.append(listener
)
240 for other
in self
.listeners
:
241 other
.Update(self
.colour
, self
.thickness
)
244 #----------------------------------------------------------------------
246 class DoodleFrame(wx
.Frame
):
247 def __init__(self
, parent
):
248 wx
.Frame
.__init
__(self
, parent
, -1, "Doodle Frame", size
=(800,600),
249 style
=wx
.DEFAULT_FRAME_STYLE | wx
.NO_FULL_REPAINT_ON_RESIZE
)
250 doodle
= DoodleWindow(self
, -1)
252 #----------------------------------------------------------------------
254 if __name__
== '__main__':
255 app
= wx
.PySimpleApp()
256 frame
= DoodleFrame(None)