4 This module contains the DoodleWindow class which is a window that you
5 can do simple drawings upon.
9 from wxPython
.wx
import *
11 #----------------------------------------------------------------------
13 class DoodleWindow(wxWindow
):
14 menuColours
= { 100 : 'Black',
34 def __init__(self
, parent
, ID
):
35 wxWindow
.__init
__(self
, parent
, ID
, style
=wxNO_FULL_REPAINT_ON_RESIZE
)
36 self
.SetBackgroundColour("WHITE")
39 self
.SetColour("Black")
46 # hook some mouse events
47 EVT_LEFT_DOWN(self
, self
.OnLeftDown
)
48 EVT_LEFT_UP(self
, self
.OnLeftUp
)
49 EVT_RIGHT_UP(self
, self
.OnRightUp
)
50 EVT_MOTION(self
, self
.OnMotion
)
52 # the window resize event and idle events for managing the buffer
53 EVT_SIZE(self
, self
.OnSize
)
54 EVT_IDLE(self
, self
.OnIdle
)
56 # and the refresh event
57 EVT_PAINT(self
, self
.OnPaint
)
65 if hasattr(self
, "menu"):
71 """Initialize the bitmap used for buffering the display."""
72 size
= self
.GetClientSize()
73 self
.buffer = wxEmptyBitmap(size
.width
, size
.height
)
74 dc
= wxBufferedDC(None, self
.buffer)
75 dc
.SetBackground(wxBrush(self
.GetBackgroundColour()))
78 self
.reInitBuffer
= false
81 def SetColour(self
, colour
):
82 """Set a new colour and make a matching pen"""
84 self
.pen
= wxPen(wxNamedColour(self
.colour
), self
.thickness
, wxSOLID
)
88 def SetThickness(self
, num
):
89 """Set a new line thickness and make a matching pen"""
91 self
.pen
= wxPen(wxNamedColour(self
.colour
), self
.thickness
, wxSOLID
)
95 def GetLinesData(self
):
99 def SetLinesData(self
, lines
):
100 self
.lines
= lines
[:]
106 """Make a menu that can be popped up later"""
108 keys
= self
.menuColours
.keys()
111 text
= self
.menuColours
[k
]
112 menu
.Append(k
, text
, kind
=wxITEM_CHECK
)
113 EVT_MENU_RANGE(self
, 100, 200, self
.OnMenuSetColour
)
114 EVT_UPDATE_UI_RANGE(self
, 100, 200, self
.OnCheckMenuColours
)
117 for x
in range(1, self
.maxThickness
+1):
118 menu
.Append(x
, str(x
), kind
=wxITEM_CHECK
)
119 EVT_MENU_RANGE(self
, 1, self
.maxThickness
, self
.OnMenuSetThickness
)
120 EVT_UPDATE_UI_RANGE(self
, 1, self
.maxThickness
, self
.OnCheckMenuThickness
)
124 # These two event handlers are called before the menu is displayed
125 # to determine which items should be checked.
126 def OnCheckMenuColours(self
, event
):
127 text
= self
.menuColours
[event
.GetId()]
128 if text
== self
.colour
:
132 def OnCheckMenuThickness(self
, event
):
133 if event
.GetId() == self
.thickness
:
139 def OnLeftDown(self
, event
):
140 """called when the left mouse button is pressed"""
142 self
.x
, self
.y
= event
.GetPositionTuple()
146 def OnLeftUp(self
, event
):
147 """called when the left mouse button is released"""
148 if self
.HasCapture():
149 self
.lines
.append( (self
.colour
, self
.thickness
, self
.curLine
) )
154 def OnRightUp(self
, event
):
155 """called when the right mouse button is released, will popup the menu"""
156 pt
= event
.GetPosition()
157 self
.PopupMenu(self
.menu
, pt
)
161 def OnMotion(self
, event
):
163 Called when the mouse is in motion. If the left button is
164 dragging then draw a line from the last event position to the
165 current one. Save the coordinants for redraws.
167 if event
.Dragging() and event
.LeftIsDown():
168 dc
= wxBufferedDC(wxClientDC(self
), self
.buffer)
171 pos
= event
.GetPositionTuple()
172 coords
= (self
.x
, self
.y
) + pos
173 self
.curLine
.append(coords
)
174 dc
.DrawLine(self
.x
, self
.y
, pos
[0], pos
[1])
179 def OnSize(self
, event
):
181 Called when the window is resized. We set a flag so the idle
182 handler will resize the buffer.
184 self
.reInitBuffer
= true
187 def OnIdle(self
, event
):
189 If the size was changed then resize the bitmap used for double
190 buffering to match the window size. We do it in Idle time so
191 there is only one refresh after resizing is done, not lots while
194 if self
.reInitBuffer
:
199 def OnPaint(self
, event
):
201 Called when the window is exposed.
203 # Create a buffered paint DC. It will create the real
204 # wxPaintDC and then blit the bitmap to it when dc is
205 # deleted. Since we don't need to draw anything else
206 # here that's all there is to it.
207 dc
= wxBufferedPaintDC(self
, self
.buffer)
210 def DrawLines(self
, dc
):
212 Redraws all the lines that have been drawn already.
215 for colour
, thickness
, line
in self
.lines
:
216 pen
= wxPen(wxNamedColour(colour
), thickness
, wxSOLID
)
219 apply(dc
.DrawLine
, coords
)
223 # Event handlers for the popup menu, uses the event ID to determine
224 # the colour or the thickness to set.
225 def OnMenuSetColour(self
, event
):
226 self
.SetColour(self
.menuColours
[event
.GetId()])
228 def OnMenuSetThickness(self
, event
):
229 self
.SetThickness(event
.GetId())
232 # Observer pattern. Listeners are registered and then notified
233 # whenever doodle settings change.
234 def AddListener(self
, listener
):
235 self
.listeners
.append(listener
)
238 for other
in self
.listeners
:
239 other
.Update(self
.colour
, self
.thickness
)
242 #----------------------------------------------------------------------
244 class DoodleFrame(wxFrame
):
245 def __init__(self
, parent
):
246 wxFrame
.__init
__(self
, parent
, -1, "Doodle Frame", size
=(800,600),
247 style
=wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE
)
248 doodle
= DoodleWindow(self
, -1)
250 #----------------------------------------------------------------------
252 if __name__
== '__main__':
253 app
= wxPySimpleApp()
254 frame
= DoodleFrame(None)