12.7 An Improved Implementation

The solution to the problem outlined previously is valuable to understand because it will help you recognize the principles behind many professional graphics systems, including the TKinter graphics system used by Python. It also helps you understand what is happening in the graphics systems used in the Java programming language. Another benefit of the solution is that once you have the mechanism in place to solve the current problem, you will be able to implement a move method for all graphics objects very easily.

The solution to the problem begins with two additional instance variables for the GeometricObject class and one additional instance variable and one more method for the Canvas class. For the GeometricObject, one variable will keep track of whether the object has been drawn. We might call this instance variable _ _visible. The second instance variable, _ _myCanvas, will keep track of the Canvas on which the object is drawn. The additional instance variable for the Canvas object, _ _visibleObjects, will allow the Canvas to remember an ordered list of the objects it has drawn.

To better understand the importance of these three instance variables, let’s think about what will happen when we make a call like the following: theCanvas.draw(myLine).

  1. Set the value of the _ _visible instance variable of the line to True.

  2. Set the value of the _ _myCanvas instance variable of the line to point to theCanvas. At the moment this may seem circular to you, but it should become clear when we talk about what happens when you call setColor.

  3. Call the line’s _draw method.

  4. Add the line object to the _ _visibleObjects instance variable of the canvas.

At the end of this sequence, the line will be drawn on the canvas. More importantly, the line will now “remember” which canvas it was drawn on, and the canvas will know all the objects that have been drawn on it.

Next, let’s consider the sequence of events that occurs when we make a call to change the color or width of the line such as myLine.setColor('red').

  1. Modify the _ _lineColor instance variable of the line to have the new value of 'red'.

  2. If the _ _visible instance variable is True, then use the _ _myCanvas instance variable to call the method drawAll on the canvas.

In the Canvas class, the new drawAll method clears the canvas and redraws all objects on the canvas in the same order as they were drawn originally. Although we may not need to redraw all the objects on the canvas, it would be more work to figure out which objects need to be redrawn than it would be to just redraw everything. The new design for our classes is shown in FIGURE 12.8. This figure includes all the new instance variables and methods we have discussed. In UML, abstract classes and abstract methods are indicated by putting the names in italics. Thus, in Figure 12.8, GeometricObject and the _draw method in that class are italicized.

A class diagram shows a new design to allow proper color and width changes

FIGURE 12.8 New design to allow proper color and width changes.

Even though we have made some major improvements to the functionality of the Point and Line classes, we have actually changed only the Canvas and GeometricObject classes. LISTING 12.8 presents the new version of the Canvas class. Relative to our earlier implementation in Listing 12.3, we have added two new methods: drawAll and addShape. In addition, we have made small modifications to draw and _ _init_ _.

Image

LISTING 12.8 A new and improved Canvas class

The modifications to _ _init_ _ and draw affect the initialization and updating of the _ _visibleObjects instance variable. When a canvas is first created, the list of objects drawn on the canvas is initialized to an empty list. Whenever draw is called, the gObject passed as a parameter is appended to the end of the list. Consequently, all objects that are visible on the canvas are stored in the _ _visibleObjects list, and the order in which they were drawn is preserved.

The addShape method is simply a convenient way to add an object to the _ _visibleObjects list. The reason we do not call _ _visibleObjects.append directly is that by consistently using the addShape method, we limit any dependencies on how we represent the objects drawn on the canvas to one method. Imagine that sometime in the future you decide to use a dictionary, rather than a list, to keep track of the objects on the canvas. If you had used _ _visibleObjects.append in several places, you would need to change each of those places to accommodate the new representation. However, because we have been clever and used the addShape method, we would need to change only the way we add an object to the canvas in one place.

The biggest addition to the Canvas class is the drawAll method. This method iterates over all the GeometricObject objects on the _ _visibleObjects list and has each object perform its _draw method. In this way, we can re-create whatever picture is visible on the canvas by calling a single method. This loop demonstrates polymorphism in object-oriented programming in a very powerful way. Notice that we do not need to keep a separate list of lines, points, and other shapes; instead, we need only one list of objects. Because each object inherits from GeometricObject and provides a _draw method, Python finds the correct _draw method for each object.

Also notice that the first line of the method calls self._ _screen.reset(). The reset method of the screen creates a blank canvas by erasing anything that the turtle has previously drawn, and puts the turtle in the center of the canvas again.

LISTING 12.9 shows the new GeometricObject class, which has fairly small changes. We have added two new setter methods: setVisible and setCanvas. In addition, the setColor and setWidth methods have been modified to call the drawAll method whenever the object being changed is visible.

Image

LISTING 12.9 A new and improved GeometricObject class

Now, if we run the test2 code in Listing 12.7, FIGURE 12.9 shows that the changes made to our lines after being drawn do take effect: line1 is red and line2 has a width of 4.

A Python Turtle Graphics window shows two lines crossing each other, in which the thickness of both the lines are almost same.

FIGURE 12.9 Improved code allows color and width changes.

© 2001–2019 Python Software Foundation. All Rights Reserved.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.225.95.216