$ mkdir ~/cs170/labs/lab7 $ cd ~/cs170/labs/lab7
Hand in your class structures at the beginning of class. And remember, now is not the time to be working on it. I will look at them this evening, and upload comments to inquire by tomorrow.
Let's make these Wednesday quizzes a regular event. This quiz will be only on classes and objects. We'll worry about Inheritance for next week. So, be prepared for a Quiz at the beginning of class on Wednesday.
We now have a mechanism to create our own data types, which is pretty neat. One of the major benefits to this is reusability of code. However, there are some instances where your current knowledge of classes would cause your code to not be reusable in certain circumstances. For example, when something doesn't fit directly into the templates we have created for an object. Let's see how inheritance can alleviate that for us today.
One of the more classical examples of Inheritance is describing animals. There is a well known hierarchy of animals, based off of genus, species, phylum, etc. However, that can be a little bit complicated and overwhelming. So, we'll focus on one common type of animal: dogs.
This is a very simplistic, directed, and less that useful example of inheritance. Hopefully it give you an intuition as far as the syntax and the meaning behind inheritance.
The file dog.py contains a declaration for a
Dog
class. Save this file to your directory and study it. Notice what
instance variables and methods are provided. The file also contains
some code that runs the actual program. Make sure you understand
what it does, and how.
One use of inheritance is to change the behavior of specific
methods. Create a a class called Dog
. Override the speak method
of the Dog class by defining a method in the
Pomeranian
class with the same method signature. The
method should print something typical of a Pomeranian.
Modify the program to add statements to create an instance of the
Pomeranian class and make it speak (do not remove Spot). Run
the program. Both dogs should speak something different because
both classes have different bodies for the speak
method. Notice that you did not define the __init__
method for the Pomeranian
class and yet you are still
able to call it because it was inherited from the Dog
class.
In addition to replacing the behavior of a method in the parent
class it is also possible to extend the behavior of a method in the
parent class. Create a class
called Labrador
in the same file that also extends
Dog
.
Add a second parameter to the __init__
method that
specifies the color of the lab and store the lab's color in an
attribute. Again override the speak method with something
typical of a lab. Also include something about the lab's color in
the speak
print statement.
Modify your program by adding statements to create a
Labrador. Be sure to call the constructor method that
specifies the name and the color. Also add a statement to make it
speak. Run the program. The dog and Pomeranian should speak, but
there should be an error with the lab. The name
attribute is not defined because the Dog
class's __init__
method was overridden in the
Labrador class. To fix this add a call to the
Dog class's __init__
method by
using built-in method super
by adding the following
statement to the Labrador's __init__
method:
super().__init__(name)
Run the dog_test program to verify that the program now works.
>>> spot = Dog("Spot") >>> spot.speak() Spot says Woof. >>> bandit = Pomeranian("Bandit") >>> bandit.speak() Bandit says Squeak. >>> spike = Labrador("Spike", "Blond") Spike, the Blond Labrador says Bark.
Another use of Inheritance is to allow us to abstract the core components of a classification of objects, to make our code more general. For example, in Tkinter the same pieces of data really represent most of the things that can be drawn on the screen.
Today, you will make a class structure that will allow you to represent an arbitrary shape. You will then draw those shapes to a Tk canvas.
Again, I would like you to start on paper. Have myself check your paper work before you get started coding. You should try the paper pseudo-code before you look at the hint. The hint is there if you are completely lost, however.
In a file called drawing_shapes.py, create a class called
Shape
. This class should have all the attributes
necessary to draw a generic shape, as well as any methods that you can
use to put the generic shapes onto a tk window. For now, this shape
can be drawn as just a dot on the canvas.
You should have at least 3 shapes that inherit the generic Shape
class: Circle
, Square
, and
Triangle
. You should use the currently defined methods
in the Shape class when appropriate, and override methods when you
need to.
Use these three shapes to create an interesting drawing on your Tk window.
At the very least, your Shape class needs an attribute for the canvas, as well as the location of the shape on the canvas. Depending on how creative you get, you might also want a fill color.
You also need to be able to draw the shape, so you will at least need a method for that. For this generic shape, just draw a dot at the location stored in the Shape class.
Your other shapes need a slight modification to the Shape
constructor. For example, Circle
needs a radius
for drawing, whereas Triangle
and
Square
need a side length in order to draw.
Override the constructor, but don't forget to call super's
constructor as well!
You will also need to override the draw method to handle drawing the new shapes.
Right now, any one with programming experience can probably draw using your program. However, that really limits the amount of users you can have with this setup. A better setup would allow users to click on the canvas to draw.
Add to the functionality to allow users to draw by clicking on the canvas. You will need some mechanism that allows users to select which shape they want to draw next. You can either bind keyboard listeners that select the shapes, or you can explore the Tk button widget to allow users to select a shape based on mouse clicks as well.
You may need to alter your classes slightly for this, since it will be hard to determine the size of the shapes to get drawn. Unless...
If you implement a mouse motion listener properly, you can actually allow for a shape to get re-sized as they get drawn. You just have to make sure that you remove the previous shape that was drawn when you redraw the new shape.
This one behaves a little bit funny. You will have to register the mouse motion listener on a mouse press, and "unregister" the listener on mouse release. Take a look at the tkinter documentation to see how this works.
Again, this might require some slight modifications to your classes.
When you have finished, create a tar file of your lab7
directory. To create a tar file, execute the following commands:
cd ~/cs170/labs tar czvf lab7.tgz lab7/
To submit your activity, go to cseval.roanoke.edu. You should
see an available assignment called Lab Assignment 7
.
Make sure you include a header listing the authors of the file.