Python Programming in Context
Python Programming in ContextChapter 12ObjectivesTo introduce the concept of inheritanceTo create a working object-oriented graphics packageTo provide another example of object-oriented design
GoalThis is what we want to be able to doDraw on a canvasListing 12.1def drawHouse():myCanvas = Canvas(800,600)house = Rectangle(Point(-100,-100),Point(100,100))house.setFill('blue')door = Rectangle(Point(-50,-100),Point(0,75))door.setFill('brown')roof1 = Line(Point(-100,100),Point(0,200))roof2 = Line(Point(0,200),Point(100,100))roof1.setWidth(3)roof2.setWidth(3)myCanvas.draw(house)myCanvas.draw(door)myCanvas.draw(roof1)myCanvas.draw(roof2)sun = Circle(Point(-150,250),20)sun.setFill('yellow')myCanvas.draw(sun)for i in range(-150,150): # move the sun across the skysun.move(1,0)Figure 12.1Inheritance HierarchyIS-A RelationshipOne object is a more specific instance of anotherHAS-A RelationshipOne object uses another objectExamplesA rectangle is-a polygonA square is-a rectangleFigure 12.2Figure 12.3Listing 12.2myCanvas = Canvas(800,600)myLine = Line(Point(-100,-100),Point(100,100))myCanvas.draw(myLine)Figure 12.4Implementing the Canvas ClassA canvas will have a width and a heightA turtle will do all the drawing
Listing 12.3class Canvas: def __init__(self,w,h): self.turtle = turtle.Turtle() self.screen = turtle.Screen() self.width = w self.height = h
self.screen.setup(width=self.width,height=self.height) self.turtle.hideturtle()
def draw(self,gObject): self.turtle.up() self.screen.tracer(0) gObject._draw(self.turtle) self.screen.tracer(1)
Geometric ObjectLine colorLine widthDrawGeometric objects dont really know how to draw themselvesSubclasses will know how to draw themselvesCall the _draw method from each objectListing 12.4class GeometricObject: def __init__(self): self.lineColor = 'black' self.lineWidth = 1
def getColor(self): return self.lineColor
def getWidth(self): return self.lineWidth
def setColor(self,color): self.lineColor = color
def setWidth(self,width): self.lineWidth = width
def _draw(self,someturtle): print("Error: You must define _draw in subclass")PointX and Y locationInherits color and widthDraw makes a dot
Listing 12.5class Point(GeometricObject): def __init__(self, x,y): super().__init__() self.x = x self.y = y
def getCoord(self): return (self.x,self.y)
def getX(self): return self.x
def getY(self): return self.y
def _draw(self,aturtle): aturtle.goto(self.x,self.y) aturtle.dot(self.lineWidth,self.lineColor) LineHas two pointsColor and width are inheritedDraws a line between by placing turtle on one point and moving to the otherListing 12.6class Line(GeometricObject): def __init__(self, p1,p2): super().__init__() self.p1 = p1 self.p2 = p2 def getP1(self): return self.p1 def getP2(self): return self.p2 def _draw(self,aturtle): aturtle.color(self.getColor()) aturtle.width(self.getWidth()) aturtle.goto(self.p1.getCoord()) aturtle.down() aturtle.goto(self.p2.getCoord())Figure 12.5Figure 12.6RedesignCurrent design works wellThe following example shows a problemChanging the color of the line after the line has been drawnNew color will not be shownNeed to redraw the lineBut, then it will be out of place with respect to all the other objectsNeed to redraw ALL OF THEMNeed to keep track of all object on canvas in the order they were createdListing 12.7 def test2(): myCanvas = Canvas(500,500) myLine = Line(Point(-100,-100),Point(100,100)) myOtherLine = Line(Point(-100,100),Point(100,-100)) myLine.setWidth(4) myOtherLine.setWidth(4) myCanvas.draw(myLine) myCanvas.draw(myOtherLine) myLine.setColor('red')Figure 12.7Listing 12.8class Canvas: def __init__(self,w,h): self.width = w self.height = h self.visibleObjects = [] self.turtle = turtle.Turtle() self.screen = turtle.Screen() self.screen.setup(width=self.width,height=self.height) self.turtle.hideturtle()
def drawAll(self): self.screen.reset() self.screen.tracer(0) for shape in self.visibleObjects: shape._draw(self.turtle) self.screen.tracer(1) self.turtle.hideturtle()
def addShape(self,shape): self.visibleObjects.append(shape)
def draw(self,gObject): gObject.setCanvas(self) gObject.setVisible(True) self.turtle.up() self.screen.tracer(0) gObject._draw(self.turtle) self.screen.tracer(1) self.addShape(gObject)Listing 12.9 (Part 1)class GeometricObject:
def __init__(self): self.lineColor = 'black' self.lineWidth = 1 self.visible = False self.myCanvas = None
def setColor(self,color): self.lineColor = color if self.visible: self.myCanvas.drawAll()
def setWidth(self,width): self.lineWidth = width if self.visible:Listing 12.9 (Part 2) self.myCanvas.drawAll()
def getColor(self): return self.lineColor
def getWidth(self): return self.lineWidth
def _draw(self): print ("Error: You must define _draw in subclass")
def setVisible(self,vFlag): self.visible = vFlag
def setCanvas(self,theCanvas): self.myCanvas = theCanvas
PolygonPolygons are defined by a list of pointsDraw the polygon by moving the turtle from point to pointConnect the last point back to the firstFigure 12.8Figure 12.9RectangleNeeds two opposing diagonal pointsCan compute the other two pointsDraw as polygonFigure 12.10Figure 12.11
Shape
Circle
Square
Ellipse Polygon
Rectangle Triangle
GeometricObject
ShapePointLine
Canvas
Circle Rectangle
Square
Triangle
Ellipse Polygon
Circle Rectangle
Square
Triangle
Ellipse
x y
Polygon
Shape
CanvasGeometricObject
Point
getX getY getCoord
Line
getP1 getP2
p1 p2
lineColor lineWidth
turtle objectsdrawsetWidth
setColor
__class__
__dict__
__bases__
__bases__
__dict__
__dict__
__bases__
__dict__
{p2, lineWidth, p1, lineColor}
black
1
(2)
(6)(7)
(4)
(5)
(3)
(1)
myLine
Line
GeometricObject
object
{getP1, __module__, getP2 _draw, __doc__, __init__}
{__module__, setColor, getColor, _draw, getWidth, __weakref__, __dict__, setWidth, __doc__, __init__}
__class__ black
__dict__
myLine global
1
{p2, lineWidth, p1, lineColor}
selflocal(getWidth)
Circle Rectangle
Square
Triangle
Ellipse
x y
Polygon
Shape
CanvasGeometricObject
Point
getX getY getCoord _draw
Line
getP1 getP2 _draw
p1 p2
lineColor lineWidth visible myCanvas
turtle visibleObjectsdraw drawAll getTurtlesetWidth
setColor setCanvas setVisible move
fillColor
setFill
p3
p0 p1
p2
p3
p0 p1
p2
(II.x, ur.y) ur = (20, 10)
(ur.x, II.y)II = (0, 0)
Circle
Ellipse
x y
Shape
Square
CanvasGeometricObject
Point
getX getY getCoord _draw
Line
getP1 getP2 _draw
p1 p2
lineColor lineWidth visible myCanvas
turtle Objectsdraw drawAll getTurtlesetWidth
setColor setCanvas setVisible move
fillColor
setFill
Polygoncorners
_draw move
RectanglelowerLeft upperRightgetLowerLeft getUpperRight
Trianglep1 p2 p3getP1 getP2 getP3