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)