A
more highly interactive graphics program tracks the position of the mouse cursor
in a canvas and responds to events such as mouse button presses, cursor
movement, and dragging (a combination of the two). For example, to draw an oval, the user
might press the mouse button at the ovalÕs upper left corner, drag the cursor
down to ovalÕs lower right corner, and release the mouse button.
To
develop an application that handles mouse events in a canvas, the programmer
must use a different design pattern from the one just discussed. In this new pattern, the programmer
defines a new subclass of EasyCanvas. The new subclass includes definitions of
the methods that will respond to relevant mouse events in the canvas. An instance of this class is then added
to the window, as the optional canvas argument to
the addCanvas
method. When a mouse event occurs
in the canvas, the corresponding handler method is triggered. Default handler methods that do nothing
are also defined in EasyCanvas, but if the
programmer overrides the relevant method in her subclass, the application can
then respond to the event appropriately.
Here are the types of mouse events and their handler methods.
EasyCanvas Method |
What it
does |
mousePressed(event) |
Triggered
when the left mouse button is pressed.
event.x and event.y hold the mouse cursorÕs coordinates. |
mouseReleased(event) |
Triggered
when the left mouse button is released.
event.x and event.y hold the mouse cursorÕs coordinates. |
mouseMoved(event) |
Triggered
when the mouse is moved. event.x and event.y hold the mouse cursorÕs coordinates. |
mouseDragged(event) |
Triggered
when the mouse is moved with left mouse button pressed. event.x and event.y hold the
mouse cursorÕs coordinates. |
mouseClicked(event) |
Triggered
when the left mouse button is clicked.
event.x and event.y hold the mouse cursorÕs coordinates. |
The
application window shown in Figure 25 contains two colored canvases. The user can draw ovals by dragging the
mouse in the left canvas, and can show the coordinates of a mouse press in the
right canvas. The command button
clears the ovals in the left canvas.
|
The code for this application includes
the definition of two new classes called LeftCanvas and RightCanvas. Both are subclasses of EasyCanvas.
The __init__ method adds
an instance of each canvas class to the window, as shown in the next code
segment. Note that the constructor
for each new canvas class expects self, the parent window, as an argument. Also, the application window is no
longer responsible for maintaining a list of items drawn in a canvas. ThatÕs the responsibility of the new
canvas subclass.
def __init__(self):
"""Sets
up the window and widgets."""
EasyFrame.__init__(self, title = "Canvas Demo")
# Add
the labels
self.addLabel(text = "Canvas
1", row = 0, column = 0)
self.addLabel(text = "Canvas
2", row = 0, column = 1)
# Add
the canvases
self.leftCanvas = self.addCanvas(canvas
= LeftCanvas(self),
row = 1, column = 0)
rightCanvas = self.addCanvas(canvas
= RightCanvas(self),
row = 1, column = 1)
# Add
the command button
self.button = self.addButton(text
= "Clear Shapes",
row = 2, column = 0,
columnspan = 2,
command = self.clearAll)
# Command button event handler
def clearAll(self):
"""Deletes
all shapes from left canvas."""
self.leftCanvas.clearAll()
The
RightCanvas class, which draws the coordinates of each mouse
press event, is the simpler of the two new canvas classes. Its __init__ method sets its background color. When a mouse is pressed in this canvas, the
mousePressed method is triggered and receives the mouse event
object as an argument. As the next
segment shows, this method uses the coordinates contained in this event to draw
the text of the coordinates at that point on the canvas.
class RightCanvas(EasyCanvas):
"""Displays
the coordinates of the point where
the mouse is pressed."""
def __init__(self, parent):
"""Background is medium
blue."""
EasyCanvas.__init__(self,
parent, background = "#0000CC")
def mousePressed(self, event):
"""Draws the coordinates of the mouse press
in white."""
self.drawText("(" + str(event.x) + "," + str(event.y) + ")",
event.x, event.y, fill = "white")
The
LeftCanvas class must
respond to two types of mouse events, a press and a release. When a press occurs, the canvas saves
the current mouse cursor coordinates (method mousePressed). When a release occurs, if the current
mouse cursor coordinates are different from the earlier ones, the canvas uses
these two pairs of coordinates to draw an oval (method mouseReleased).
The canvas also maintains a list of items drawn in it for eventual
deletion (method clearAll). The code for LeftCanvas is shown next.
class LeftCanvas(EasyCanvas):
"""This canvas supports the drawing of ovals.
The user
presses the mouse button at one corner and drags to
the other corner before releasing."""
def __init__(self, parent):
"""Background is medium red. Items drawn are tracked
for later erasing."""
EasyCanvas.__init__(self,
parent, background = "#CC0000")
self._items = list()
def mousePressed(self, event):
"""Sets the first corner of the oval's
bounding rectangle."""
self._x0 = event.x
self._y0 = event.y
def mouseReleased(self, event):
"""Sets the second corner of the oval's
bounding rectangle.
Draws an oval filled in blue and saves its id."""
if self._x0 != event.x and self._y0 != event.y:
item = self.drawOval(self._x0,
self._y0,
event.x, event.y, fill = "#0000CC")
self._items.append(item)
def clearAll(self):
"""Deletes all ovals from left
canvas."""
for item in self._items:
self.deleteItem(item)
self._items = list()
Although
the second design pattern for the use of canvases is more complicated than the
first one, it actually simplifies the structure of the application, by
separating the responsibilities for managing each canvas from the
responsibilities for managing the window.