from graphics import GraphWin, Point, Circle win = GraphWin() win2 = GraphWin()
With two windows on your screen, you can now draw graphics objects on both; however note that single graphics objects can only be drawn to one window at a time.
p = Point(30, 40)
--------------------------------------------------------------------------- GraphicsError Traceback (most recent call last) <ipython-input-4-21bc946d1a56> in <module>() ----> 1 p.draw(win2) ~/Library/Python/3.6/lib/python/site-packages/graphics.py in draw(self, graphwin) 479 is already visible.""" 480 --> 481 if self.canvas and not self.canvas.isClosed(): raise GraphicsError(OBJ_ALREADY_DRAWN) 482 if graphwin.isClosed(): raise GraphicsError("Can't draw to closed window") 483 self.canvas = graphwin GraphicsError: Object currently drawn
We see that our point
p cannot be drawn twice! It was already drawn on
win, and therefore it makes no sense to draw it again on
win2. No problem, if we wished it to be drawn on
win2, we simply "undraw" it and then draw it on the correct window.
Here we explore some basic ideas of how objects names work and when what we think is object duplication isn't really duplication!
Before we get into it, let's make a new window, called
win, but let's close our original one first:
Then, let's make a new window and assign it to
win = GraphWin("Face Demo", 600, 600)
You should be asking yourself where did the extra information in the constructor call to
GraphWin come from!? Well, first, it's in the slides and in the documentation (try:
help(GraphWin)). Secondly, we are seeing optional function parameters at play here (whether we are talking about class methods, a class constructor call or a plain-ol' function, they are all just functions in the end.)
How does this work? Well, in this first time introduction, we'll keep it light until we hit the 'Functions' topic in fully in a week or so.
GraphWin's constructor call allows us to use default values for the title and size of the window. The order of these parameters are defined in the
graphics.py file, and can be understood through that call to
help I mention above. Once you know the order you can simply call it as:
win = GraphWin("Face Demo", 600, 600)
That is, the title, width and height have to be provided in that order.
Now, the fun thing what if you just want to modify the title, but not the size?
win = GraphWin("Face Demo")
win = GraphWin(title="Face Demo")
What if you don't care about the title, or the width? You just want to give the window a custom height?
win = GraphWin(height=400)
The beauty of optional parameters is they are named! You can leave off the ones you don't care about and provide only the ones you do, so long as you name them explicitly.
Our first example of creating
win didn't use names. These optional parameters, when given unnamed suddenly become required, even if you intend on only changing one default value! We'll talk more about this later.
Next… let create an eye!
In our class example, we discussed the start of making a face using the
graphics library. So, naturally we start with the eyes. We begin by making a left eye from the
Circle class, called
left_eye. We set the fill color to red, the outline to yellow and then draw it to the window.
left_eye = Circle(Point(80, 50), 20) left_eye.setFill('yellow') left_eye.setOutline('red') left_eye.draw(win)
Circle(Point(80.0, 50.0), 20)
Let's move the eye to place it in a better location. We do so using
.move() on the
Circle instance we called
left_eye. The movement is given as a difference of pixel positions, not absolute position. So we are moving the eye 200 pixels right on the X axis from it's current position of X = 80, and 150 pixels down on the Y axis from it's current position of Y = 50.
Ah! Not quite right, so we adjust once more. This time we move our eye left by -50 pixels on the X axis, but we move 0 pixels in the Y axis.
Now, we need a right eye. Let's call it…
right_eye! Fine, so you may instictively try this the following assignment, thinking "Hey, I'll just assign another variable the same 'value' as
left_eye". Sound logic, right? Will it work? Let's investigate.
right_eye = left_eye right_eye.move(20, 0) right_eye.draw(win)
--------------------------------------------------------------------------- GraphicsError Traceback (most recent call last) <ipython-input-22-d3e765be12c2> in <module>() 1 right_eye = left_eye 2 right_eye.move(20, 0) ----> 3 right_eye.draw(win) ~/Library/Python/3.6/lib/python/site-packages/graphics.py in draw(self, graphwin) 479 is already visible.""" 480 --> 481 if self.canvas and not self.canvas.isClosed(): raise GraphicsError(OBJ_ALREADY_DRAWN) 482 if graphwin.isClosed(): raise GraphicsError("Can't draw to closed window") 483 self.canvas = graphwin GraphicsError: Object currently drawn
We simply assigned
left_eye. Then we moved it (before drawing it, or so we thought) and then tried to draw it. You should have noticed:
left_eyemoved before we even drew the
right_eye. Huh? Why?
right_eye, it claims it was already drawn. Well, that's frustrating.
What you inadvertantely did was 'alias' an object. You created a
Circle instance that you named
left_eye. Then, the assignment operation of
right_eye = left_eye did not create a new object, but simply gave your existing
Circle instance a second name,
You can verify object ID numbers using the
id() function. Each object has a unique identifier given to it. If you give anobject two, or more names, then
id() will return the same ID number for all those names, since they refer to the same object in memory.
Yup, our eyes have the same ID. So, how do we resolve this? The graphics library endows its classes with a helpful method called
# First, move back our left eye which erroneously moved! left_eye.move(-20, 0) # Now, clone the eye! right_eye = left_eye.clone()
Great! Let's confirm they are two different objects:
So, they are distinct objects now, perfect. Let's move the right eye to its final spot.
right_eye.move(100, 0) right_eye.draw(win)
Circle(Point(330.0, 200.0), 20)
This demonstrates the basics of Pythons name binding rules! If you like the nitty-gritty details, feel free to read the official documentation at: https://docs.python.org/3/reference/executionmodel.html