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
)
59 # When the window is destroyed, clean up resources.
60 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 = wxEmptyBitmap(size
.width
, size
.height
)
73 dc
= wxBufferedDC(None, self
.buffer)
74 dc
.SetBackground(wxBrush(self
.GetBackgroundColour()))
77 self
.reInitBuffer
= False
80 def SetColour(self
, colour
):
81 """Set a new colour and make a matching pen"""
83 self
.pen
= wxPen(wxNamedColour(self
.colour
), self
.thickness
, wxSOLID
)
87 def SetThickness(self
, num
):
88 """Set a new line thickness and make a matching pen"""
90 self
.pen
= wxPen(wxNamedColour(self
.colour
), self
.thickness
, wxSOLID
)
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
=wxITEM_CHECK
)
112 EVT_MENU_RANGE(self
, 100, 200, self
.OnMenuSetColour
)
113 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
=wxITEM_CHECK
)
118 EVT_MENU_RANGE(self
, 1, self
.maxThickness
, self
.OnMenuSetThickness
)
119 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
:
131 def OnCheckMenuThickness(self
, event
):
132 if event
.GetId() == self
.thickness
:
138 def OnLeftDown(self
, event
):
139 """called when the left mouse button is pressed"""
141 self
.x
, self
.y
= event
.GetPositionTuple()
145 def OnLeftUp(self
, event
):
146 """called when the left mouse button is released"""
147 if self
.HasCapture():
148 self
.lines
.append( (self
.colour
, self
.thickness
, self
.curLine
) )
153 def OnRightUp(self
, event
):
154 """called when the right mouse button is released, will popup the menu"""
155 pt
= event
.GetPosition()
156 self
.PopupMenu(self
.menu
, pt
)
160 def OnMotion(self
, event
):
162 Called when the mouse is in motion. If the left button is
163 dragging then draw a line from the last event position to the
164 current one. Save the coordinants for redraws.
166 if event
.Dragging() and event
.LeftIsDown():
167 dc
= wxBufferedDC(wxClientDC(self
), self
.buffer)
170 pos
= event
.GetPositionTuple()
171 coords
= (self
.x
, self
.y
) + pos
172 self
.curLine
.append(coords
)
173 dc
.DrawLine(self
.x
, self
.y
, pos
[0], pos
[1])
178 def OnSize(self
, event
):
180 Called when the window is resized. We set a flag so the idle
181 handler will resize the buffer.
183 self
.reInitBuffer
= True
186 def OnIdle(self
, event
):
188 If the size was changed then resize the bitmap used for double
189 buffering to match the window size. We do it in Idle time so
190 there is only one refresh after resizing is done, not lots while
193 if self
.reInitBuffer
:
198 def OnPaint(self
, event
):
200 Called when the window is exposed.
202 # Create a buffered paint DC. It will create the real
203 # wxPaintDC and then blit the bitmap to it when dc is
204 # deleted. Since we don't need to draw anything else
205 # here that's all there is to it.
206 dc
= wxBufferedPaintDC(self
, self
.buffer)
209 def DrawLines(self
, dc
):
211 Redraws all the lines that have been drawn already.
214 for colour
, thickness
, line
in self
.lines
:
215 pen
= wxPen(wxNamedColour(colour
), thickness
, wxSOLID
)
218 apply(dc
.DrawLine
, coords
)
222 # Event handlers for the popup menu, uses the event ID to determine
223 # the colour or the thickness to set.
224 def OnMenuSetColour(self
, event
):
225 self
.SetColour(self
.menuColours
[event
.GetId()])
227 def OnMenuSetThickness(self
, event
):
228 self
.SetThickness(event
.GetId())
231 # Observer pattern. Listeners are registered and then notified
232 # whenever doodle settings change.
233 def AddListener(self
, listener
):
234 self
.listeners
.append(listener
)
237 for other
in self
.listeners
:
238 other
.Update(self
.colour
, self
.thickness
)
241 #----------------------------------------------------------------------
243 class DoodleFrame(wxFrame
):
244 def __init__(self
, parent
):
245 wxFrame
.__init
__(self
, parent
, -1, "Doodle Frame", size
=(800,600),
246 style
=wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE
)
247 doodle
= DoodleWindow(self
, -1)
249 #----------------------------------------------------------------------
251 if __name__
== '__main__':
252 app
= wxPySimpleApp()
253 frame
= DoodleFrame(None)