Fall 2011 CSCI 220 Week 5

= Objects and Graphics =

Overview
Most modern computer systems are built with an object-oriented (OO) approach. It is a set of principles for designing and implementing software. We will introduce objects by way of computer graphics.

Graphical programming is a lot of fun and provides a great vehicle for learning about objects. GUI frameworks can be complicated, but also powerful. We will introduce graphics and objects to you using a graphics library provided by our textbook. The library is a wrapper around Tkinter that makes it more suitable for beginning programmers.

The Object of Objects
Object oriented development views complex systems as the interaction of simpler objects. The term objects here is being used in a specific technical sense. Part of the difficulty in picking up object oriented programming is the vocabulary.

Objects:
 * know stuff (they contain data)
 * can do stuff (they have operations)
 * interact by sending messages by requesting an object to perform one of its operations

Example:

Consider a data processing system for colleges and universities. For starters, we must keep track of records on the students that attend the school. Each student could be represented as an object, which might contain the following data:
 * GPA
 * Name
 * ID
 * Address
 * etc

An example operation or message that could be asked of a student object is printStudentAddress.

Objects may refer to other objects. For example, we may also have a course object that would know what student objects are in a given class. One example operation could be addStudent, which would add a student object to a course.

Simple Graphics Programming
COPY graphics.py INTO THE FOLDER THAT CONTAINS YOUR PROGRAM.

Your first program: import graphics
 * 1) Import the graphics package

win = graphics.GraphWindow
 * 1) Create an empty window

This window is an object that is referenced by the variable win. We can communicate to the object through this reference by its methods. One of which is the close method/message:

win.close
 * 1) Close the window

It gets tedious to add graphics in front of all of the methods in the graphics package. We can get around this by using the following modified import statement: from graphics import *

The from statement loads specific definitions from the module/package. You can either list the definitions to be imported or use the * to import all of the definitions.

Graphics windows is actually made up of pixels (picture elements). By controlling the color of each pixel we can control what is displayed. By default a GraphWin is 200 x 200 pixels. This means that there are 40,000 pixels. Assigning a color to each would be a daunting task.

The simplest object in the graphics module is a Point. A point is a location in space that is located by reference to a coordinate system. We define a point by supplying the x and y coordinates. The top-left corner of the screen is (0,0), and the bottom-right is (199,199) by default. The default color for drawing is black. Here is an example:

from graphics import *

win = GraphWin

p = Point(60,60) p.draw(win)

p2 = Point(120,20) p2.draw(win)

Then enter: >>> win.close to close the window.

With the graphics package provided by the book, we can draw circles, rectangles, ovals, polygons, lines, and text. Each of these objects is created and drawn in a similar fashion. Here is a sample:

from graphics import *

win = GraphWin('Shapes')
 * 1) Open a window

center = Point(100,100) circ = Circle(center, 30) circ.setFill('red') circ.draw(win)
 * 1) Draw a red circle centered at point (100,100) with a radius 30

label = Text(center, "Red circle") label.draw(win)
 * 1) Put a textual label in the center of the circle

rect = Rectangle(Point(30,30), Point(70,70)) rect.draw(win)
 * 1) Draw a square using a Rectangle object

line = Line(Point(30,30),Point(180,165)) line.draw(win)
 * 1) Draw a line segment using a Lien object

oval = Oval(Point(20,150), Point(180,199)) oval.draw(win)
 * 1) Draw an oval using the Oval object

Using Graphical Objects
In the example above, we manipulated several different kinds of objects: GraphWin, Point, Circle, Oval, Line, Text, and Rectangle. These are examples of classes. Every object is an instance of some class.

We can use a biological metaphor to explain the difference between a class and an instance of a class (object):
 * Fido is a dog
 * Dog is a class
 * Fido is an instance of the class Dog

We expect certain characteristics of a dog:
 * Four legs
 * Tail
 * Cold, wet nose
 * Barks

If Rex is a another instance of a Dog, we expect them to have similar properties, even though Fido and Rex might differ in specific details such as size or color.

The same holds true of our computational objects. For example, we created to instances of the class Point (p and p2). Each of these points share the same attributes: x and y coordinates. But each instance of the Point class had specific values for x and y.

To create a new instance of a class, we use a special operation called a constructor. A constructor is an expression that creates a new object. It has the general form: (, ,...)

Here  is the name of the class that we want to create a new instance of. The expressions in the parenthesis are any parameters that are necessary to create the object.

Here is a concrete example: p = Point(50,60)
 * The constructor for the Point class requires two parameters giving the x and y coordinates for the new point.
 * These values are stored as instance variables (or attributes) inside the object.
 * The resulting point is assigned to the variable p.
 * A conceptual diagram of the result is shown in Figure 4.4.

To perform an operation on an object, we send the object a message. This is done by using the dot-notation and the methods of the object: .(, ,...)

The number of parameters is determined by the method being called. Some methods require no parameters at all. Examples are: p.getX p.getY

The getX and getY methods return the x and y values of a point. Methods such as these are commonly called accessors, because they all the user to access information from the instance variables of the object.

Other methods change the state of an object's instance variables, hence changing the state of the object. All of the graphical objects have a move method. Here is the specification:

move(dx, dy): Moves the object dx units in the x direction and dy units in the y direction.

To move the point p to the right 10 units, we could use this statement: p.move(10,0)

Methods that change the state of an object are sometimes called mutators.

The move method is supplied with two simple numeric parameters. Some methods require parameters that are themselves complex objects. For example drawing a Circle into a GraphWin involves two objects: circ = Circle(Point(100,100), 30) win = GraphWin circ.draw(win)


 * The first line creates a Circle with a center located at the Point(100,100) and a radius of 30.
 * Note that we used the Point constructor to create a location for the first parameter to the Circle constructor.
 * The second line creates the GraphWin
 * The third line is a request of the circle object to draw itself into the GraphWin object win
 * Behind the scenes a lot is happening. That's the power of object-oriented programming!

There is one more gotcha that you need to be aware of when dealing with objects. If we want to make a graphical window with two circles 20 units apart, we might try something like this: leftEye = Circle(Point(80,50), 5) leftEye.setFill('yellow') leftEye.setOutline('red') rightEye = leftEye rightEye.move(20,0)

The basic idea is to create the left eye and then copy that into a right eye which is then moved over 20 units. This doesn't work. The problem is that there is only one Circle object, but there are two references to that object.

One solution would be to create two completely separate objects, but that is a duplication of some code. If we want to avoid that, we can use the clone method, which is available on all graphics objects (and most objects in general): leftEye = Circle(Point(80,50), 5) leftEye.setFill('yellow') leftEye.setOutline('red') rightEye = leftEye.clone # make an exact copy rightEye.move(20,0)

Interactive Graphics
Graphical interfaces can be used for input as well as output. Users typically interact with their applications by clicking on buttons, choosing items from menus, and typing information on-screen. These applications use a technique called event-driven programming.

Event-driven programming:
 * Draw a set of interface elements (widgets) and then wait for the user to do something
 * The event could be a mouse move, button click, keyboard entry, etc

An event is an object that encapsulates an event that just happened. For example, a click on a button produces a button event. This event would be passed to the button-handling code, which would perform the specified action.

Event-driven programming is different than what we have done in the past. Before we knew exactly what piece of our program was in charge at any given time. Imagine a game of catch with two people: our program and the user. In our previous style of programming our program was always in charge. It either had the ball or asked the user for a specific type of throw (e.g., input). In event-driven programming, the user has the ball and our is waiting to respond to the type of throw. Is it a curve ball, fastball, slider, etc? These would correspond to whether the event is a button click, mouse move, keyboard event, etc.

Getting Mouse Clicks
from graphics import *
 * 1) click.py

def main: win = GraphWin("Click me!") for i in range(10): p = win.getMouse print("You clicked at:", p.getX, p.getY)

main

Here is an interactive example that allows the user to draw a triangle by clicking on three points in a graphics window. If you are running in a windows environment, you can now the program using a .pyw extension and the Python text window won't show on screen. from graphics import *
 * 1) triangle.pyw

def main: win = GraphWin("Draw a triangle") win.setCoords(0.0, 0.0, 10.0, 10.0) message = Text(Point(5, 0.5), "Click on three points") message.draw(win) # Get and draw three vertices of triangle p1 = win.getMouse p1.draw(win) p2 = win.getMouse p2.draw(win) p3 = win.getMouse p3.draw(win)

# Use the Polygon object to draw the triangle triangle = Polygon(p1,p2,p3) triangle.setFill("peachpuff") triangle.setOutline("cyan") triangle.draw(win)

# Wait for another click to exit message.setText("Click anywhere to quit.") win.getMouse

main

Note: A triangle is a three sided polygon.

Handling Textual Input

 * 1) convert_gui.pyw
 * 2) Program to convert Celsius to Fahrenheit

from graphics import *

def main: win = GraphWin("Celsius Converter", 400, 300) win.setCoords(0.0, 0.0, 3.0, 4.0) # Draw the interface Text(Point(1,3), "  Celsius Temperature:").draw(win) Text(Point(1,1), "Fahrenheit Temperature:").draw(win) input = Entry(Point(2,3), 5) input.setText("0.0") input.draw(win) output = Text(Point(2,1),"") output.draw(win) button = Text(Point(1.5,2.0),"Convert It"))   button.draw(win)    Rectangle(Point(1,1.5), Point(2,2.5)).draw(win)

# wait for a mouse click win.getMouse # convert input celsius = eval(input.getText) fahrenheit = 9.0/5.0 * celsius + 32 # display output and change button output.setText(fahrenheit) button.setText("Quit") # wait for click and then quit win.getMouse win.close

main