This recipe talks about how to implement rubberbanding code for canvas objects in a wxPython application. Canvas classes in wxPython include wxPanel, wxStaticBitmap, wxGlCanvas etc.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | # This class describes a generic method of drawing rubberbands
# on a wxPython canvas object (wxStaticBitmap, wxPanel etc) when
# the user presses the left mouse button and drags it over a rectangular
# area. It has methods to return the selected area by the user as
# a rectangular 4 tuple / Clear the selected area.
# Beginning of code
class wxPyRubberBander:
""" A class to manage mouse events/ rubberbanding of a wxPython
canvas object """
def __init__(self, canvas):
# canvas object
self._canvas = canvas
# mouse selection start point
self.m_stpoint=wxPoint(0,0)
# mouse selection end point
self.m_endpoint=wxPoint(0,0)
# mouse selection cache point
self.m_savepoint=wxPoint(0,0)
# flags for left click/ selection
self._leftclicked=false
self._selected=false
# Register event handlers for mouse
self.RegisterEventHandlers()
def RegisterEventHandlers(self):
""" Register event handlers for this object """
EVT_LEFT_DOWN(self._canvas, self.OnMouseEvent)
EVT_LEFT_UP(self._canvas, self.OnMouseEvent)
EVT_MOTION(self._canvas, self.OnMouseEvent)
def OnMouseEvent(self, event):
""" This function manages mouse events """
if event:
# set mouse cursor
self._canvas.SetCursor(wxStockCursor(wxCURSOR_ARROW))
# get device context of canvas
dc= wxClientDC(self._canvas)
# Set logical function to XOR for rubberbanding
dc.SetLogicalFunction(wxXOR)
# Set dc brush and pen
# Here I set brush and pen to white and grey respectively
# You can set it to your own choices
# The brush setting is not really needed since we
# dont do any filling of the dc. It is set just for
# the sake of completion.
wbrush = wxBrush(wxColour(255,255,255), wxTRANSPARENT)
wpen = wxPen(wxColour(200, 200, 200), 1, wxSOLID)
dc.SetBrush(wbrush)
dc.SetPen(wpen)
if event.LeftDown():
# Left mouse button down, change cursor to
# something else to denote event capture
self.m_stpoint = event.GetPosition()
cur = wxStockCursor(wxCURSOR_CROSS)
self._canvas.SetCursor(cur)
# invalidate current canvas
self._canvas.Refresh()
# cache current position
self.m_savepoint = self.m_stpoint
self._selected = false
self._leftclicked = true
elif event.Dragging():
# User is dragging the mouse, check if
# left button is down
if self._leftclicked:
# reset dc bounding box
dc.ResetBoundingBox()
dc.BeginDrawing()
w = (self.m_savepoint.x - self.m_stpoint.x)
h = (self.m_savepoint.y - self.m_stpoint.y)
# To erase previous rectangle
dc.DrawRectangle(self.m_stpoint.x, self.m_stpoint.y, w, h)
# Draw new rectangle
self.m_endpoint = event.GetPosition()
w = (self.m_endpoint.x - self.m_stpoint.x)
h = (self.m_endpoint.y - self.m_stpoint.y)
# Set clipping region to rectangle corners
dc.SetClippingRegion(self.m_stpoint.x, self.m_stpoint.y, w,h)
dc.DrawRectangle(self.m_stpoint.x, self.m_stpoint.y, w, h)
dc.EndDrawing()
self.m_savepoint = self.m_endpoint # cache current endpoint
elif event.LeftUp():
# User released left button, change cursor back
self._canvas.SetCursor(wxSTOCK_CURSOR(wxCURSOR_ARROW))
self._selected = true #selection is done
self._leftclicked = false # end of clicking
def GetCurrentSelection(self):
""" Return the current selected rectangle """
# if there is no selection, selection defaults to
# current viewport
left = wxPoint(0,0)
right = wxPoint(0,0)
# user dragged mouse to right
if self.m_endpoint.y > self.m_stpoint.y:
right = self.m_endpoint
left = self.m_stpoint
# user dragged mouse to left
elif self.m_endpoint.y < self.m_stpoint.y:
right = self.m_stpoint
left = self.m_endpoint
return (left.x, left.y, right.x, right.y)
def ClearCurrentSelection(self):
""" Clear the current selected rectangle """
box = self.GetCurrentSelection()
dc=wxClientDC(self._canvas)
w = box[2] - box[0]
h = box[3] - box[1]
dc.SetClippingRegion(box[0], box[1], w, h)
dc.SetLogicalFunction(wxXOR)
# The brush is not really needed since we
# dont do any filling of the dc. It is set for
# sake of completion.
wbrush = wxBrush(wxColour(255,255,255), wxTRANSPARENT)
wpen = wxPen(wxColour(200, 200, 200), 1, wxSOLID)
dc.SetBrush(wbrush)
dc.SetPen(wpen)
dc.DrawRectangle(box[0], box[1], w,h)
self._selected = false
# reset selection to canvas size
self.ResetSelection()
def ResetSelection(self):
""" Resets the mouse selection to entire canvas """
self.m_stpoint = wxPoint(0,0)
sz=self._canvas.GetSize()
w,h=sz.GetWidth(), sz.GetHeight()
self.m_endpoint = wxPoint(w,h)
|
Rubberbanding is a common task in computer graphics for selecting specific areas of images, image canvases to perform functions like copy/cut/crop etc. This solution is straightforward, concise and elegant. There are no known issues and there could be many alternate implementations.
Fixed errors in indentation -30/12/2003 - Anand
Sugerencia Python2.4, wxPython2.6. Tenemos que poner esto:
Question for implementing. Hi everyone!
Earlier I asked a question about mouse interaction with a GUI. I have found a pretty comprehensive script that is supposed to work from http://aspn.activestate.com/ASPN/Co...n/Recipe/189744 . The problem is I'm not to savy with classes yet and I don't know how to call it and use it. Can someone guide me through this, I would be pretty grateful.
The main objective would be to set the image that is loaded as the canvas of the rubberbander and output the result.
Says we start with some pseudocode:
root=Tk() im=Image.open("filename")
rubberbandscript(........)
print output
root.mainloop()
Thanks alot, JP