1 #graphics.py
2 """Simple object oriented graphics library3 The library is designed to make it very easy for novice programmers to4 experiment with computer graphics in an object oriented fashion. It is5 written by John Zelle for use with the book "Python Programming: An6 Introduction to Computer Science" (Franklin, Beedle & Associates).7 LICENSE: This is open-source software released under the terms of the8 GPL (http://www.gnu.org/licenses/gpl.html).9 PLATFORMS: The package is a wrapper around Tkinter and should run on10 any platform where Tkinter is available.11 INSTALLATION: Put this file somewhere where Python can see it.12 OVERVIEW: There are two kinds of objects in the library. The GraphWin13 class implements a window where drawing can be done and various14 GraphicsObjects are provided that can be drawn into a GraphWin. As a15 simple example, here is a complete program to draw a circle of radius16 10 centered in a 100x100 window:17 --------------------------------------------------------------------18 from graphics import *19 def main():20 win = GraphWin("My Circle", 100, 100)21 c = Circle(Point(50,50), 10)22 c.draw(win)23 win.getMouse() # Pause to view result24 win.close() # Close window when done25 main()26 --------------------------------------------------------------------27 GraphWin objects support coordinate transformation through the28 setCoords method and pointer-based input through getMouse.29 The library provides the following graphical objects:30 Point31 Line32 Circle33 Oval34 Rectangle35 Polygon36 Text37 Entry (for text-based input)38 Image39 Various attributes of graphical objects can be set such as40 outline-color, fill-color and line-width. Graphical objects also41 support moving and hiding for animation effects.42 The library also provides a very simple class for pixel-based image43 manipulation, Pixmap. A pixmap can be loaded from a file and displayed44 using an Image object. Both getPixel and setPixel methods are provided45 for manipulating the image.46 DOCUMENTATION: For complete documentation, see Chapter 4 of "Python47 Programming: An Introduction to Computer Science" by John Zelle,48 published by Franklin, Beedle & Associates. Also see49 http://mcsp.wartburg.edu/zelle/python for a quick reference"""
50 #Version 4.1 12/29/2009
51 #* Merged Pixmap and Image class. Old Pixmap removed, use Image.
52 #Version 4.0.1 10/08/2009
53 #* Modified the autoflush on GraphWin to default to True
54 #* Autoflush check on close, setBackground
55 #* Fixed getMouse to flush pending clicks at entry
56 #Version 4.0 08/2009
57 #* Reverted to non-threaded version. The advantages (robustness,
58 #efficiency, ability to use with other Tk code, etc.) outweigh
59 #the disadvantage that interactive use with IDLE is slightly more
60 #cumbersome.
61 #* Modified to run in either Python 2.x or 3.x (same file).
62 #* Added Image.getPixmap()
63 #* Added update() -- stand alone function to cause any pending
64 #graphics changes to display.
65 #66 #Version 3.4 10/16/07
67 #Fixed GraphicsError to avoid "exploded" error messages.
68 #Version 3.3 8/8/06
69 #Added checkMouse method to GraphWin
70 #Version 3.2.3
71 #Fixed error in Polygon init spotted by Andrew Harrington
72 #Fixed improper threading in Image constructor
73 #Version 3.2.2 5/30/05
74 #Cleaned up handling of exceptions in Tk thread. The graphics package
75 #now raises an exception if attempt is made to communicate with
76 #a dead Tk thread.
77 #Version 3.2.1 5/22/05
78 #Added shutdown function for tk thread to eliminate race-condition
79 #error "chatter" when main thread terminates
80 #Renamed various private globals with _
81 #Version 3.2 5/4/05
82 #Added Pixmap object for simple image manipulation.
83 #Version 3.1 4/13/05
84 #Improved the Tk thread communication so that most Tk calls
85 #do not have to wait for synchonization with the Tk thread.
86 #(see _tkCall and _tkExec)
87 #Version 3.0 12/30/04
88 #Implemented Tk event loop in separate thread. Should now work
89 #interactively with IDLE. Undocumented autoflush feature is
90 #no longer necessary. Its default is now False (off). It may
91 #be removed in a future version.
92 #Better handling of errors regarding operations on windows that
93 #have been closed.
94 #Addition of an isClosed method to GraphWindow class.
95 #Version 2.2 8/26/04
96 #Fixed cloning bug reported by Joseph Oldham.
97 #Now implements deep copy of config info.
98 #Version 2.1 1/15/04
99 #Added autoflush option to GraphWin. When True (default) updates on
100 #the window are done after each action. This makes some graphics
101 #intensive programs sluggish. Turning off autoflush causes updates
102 #to happen during idle periods or when flush is called.
103 #Version 2.0
104 #Updated Documentation
105 #Made Polygon accept a list of Points in constructor
106 #Made all drawing functions call TK update for easier animations
107 #and to make the overall package work better with
108 #Python 2.3 and IDLE 1.0 under Windows (still some issues).
109 #Removed vestigial turtle graphics.
110 #Added ability to configure font for Entry objects (analogous to Text)
111 #Added setTextColor for Text as an alias of setFill
112 #Changed to class-style exceptions
113 #Fixed cloning of Text objects
114 #Version 1.6
115 #Fixed Entry so StringVar uses _root as master, solves weird
116 #interaction with shell in Idle
117 #Fixed bug in setCoords. X and Y coordinates can increase in
118 #"non-intuitive" direction.
119 #Tweaked wm_protocol so window is not resizable and kill box closes.
120 #Version 1.5
121 #Fixed bug in Entry. Can now define entry before creating a
122 #GraphWin. All GraphWins are now toplevel windows and share
123 #a fixed root (called _root).
124 #Version 1.4
125 #Fixed Garbage collection of Tkinter images bug.
126 #Added ability to set text atttributes.
127 #Added Entry boxes.
128 importtime, os, sys129 try: #import as appropriate for 2.x vs. 3.x
130 importtkinter as tk131 except:132 importTkinter as tk133 ##########################################################################
134 #Module Exceptions
135 classGraphicsError(Exception):136 """Generic error class for graphics module exceptions."""
137 pass
138 OBJ_ALREADY_DRAWN = "Object currently drawn"
139 UNSUPPORTED_METHOD = "Object doesn't support operation"
140 BAD_OPTION = "Illegal option value"
141 DEAD_THREAD = "Graphics thread quit unexpectedly"
142 _root =tk.Tk()143 _root.withdraw()144 defupdate():145 _root.update()146 ############################################################################
147 #Graphics classes start here
148
149 classGraphWin(tk.Canvas):150 """A GraphWin is a toplevel window for displaying graphics."""
151 def __init__(self, title="Graphics Window",152 width=200, height=200, autoflush=True):153 master =tk.Toplevel(_root)154 master.protocol("WM_DELETE_WINDOW", self.close)155 tk.Canvas.__init__(self, master, width=width, height=height)156 self.master.title(title)157 self.pack()158 master.resizable(0,0)159 self.foreground = "black"
160 self.items =[]161 self.mouseX =None162 self.mouseY =None163 self.bind("", self._onClick)164 self.height =height165 self.width =width166 self.autoflush =autoflush167 self._mouseCallback =None168 self.trans =None169 self.closed =False170 master.lift()171 ifautoflush: _root.update()172
173 def __checkOpen(self):174 ifself.closed:175 raise GraphicsError("window is closed")176 defsetBackground(self, color):177 """Set background color of the window"""
178 self.__checkOpen()179 self.config(bg=color)180 self.__autoflush()181
182 defsetCoords(self, x1, y1, x2, y2):183 """Set coordinates of window to run from (x1,y1) in the184 lower-left corner to (x2,y2) in the upper-right corner."""
185 self.trans =Transform(self.width, self.height, x1, y1, x2, y2)186 defclose(self):187 """Close the window"""
188 if self.closed: return
189 self.closed =True190 self.master.destroy()191 self.__autoflush()192 defisClosed(self):193 returnself.closed194 defisOpen(self):195 return notself.closed196 def __autoflush(self):197 ifself.autoflush:198 _root.update()199
200 def plot(self, x, y, color="black"):201 """Set pixel (x,y) to the given color"""
202 self.__checkOpen()203 xs,ys =self.toScreen(x,y)204 self.create_line(xs,ys,xs+1,ys, fill=color)205 self.__autoflush()206
207 def plotPixel(self, x, y, color="black"):208 """Set pixel raw (independent of window coordinates) pixel209 (x,y) to color"""
210 self.__checkOpen()211 self.create_line(x,y,x+1,y, fill=color)212 self.__autoflush()213
214 defflush(self):215 """Update drawing to the window"""
216 self.__checkOpen()217 self.update_idletasks()218
219 defgetMouse(self):220 """Wait for mouse click and return Point object representing221 the click"""
222 self.update() #flush any prior clicks
223 self.mouseX =None224 self.mouseY =None225 while self.mouseX == None or self.mouseY ==None:226 self.update()227 if self.isClosed(): raise GraphicsError("getMouse in closed window")228 time.sleep(.1) #give up thread
229 x,y =self.toWorld(self.mouseX, self.mouseY)230 self.mouseX =None231 self.mouseY =None232 returnPoint(x,y)233 defcheckMouse(self):234 """Return last mouse click or None if mouse has235 not been clicked since last call"""
236 ifself.isClosed():237 raise GraphicsError("checkMouse in closed window")238 self.update()239 if self.mouseX != None and self.mouseY !=None:240 x,y =self.toWorld(self.mouseX, self.mouseY)241 self.mouseX =None242 self.mouseY =None243 returnPoint(x,y)244 else:245 returnNone246
247 defgetHeight(self):248 """Return the height of the window"""
249 returnself.height250
251 defgetWidth(self):252 """Return the width of the window"""
253 returnself.width254
255 deftoScreen(self, x, y):256 trans =self.trans257 iftrans:258 returnself.trans.screen(x,y)259 else:260 returnx,y261
262 deftoWorld(self, x, y):263 trans =self.trans264 iftrans:265 returnself.trans.world(x,y)266 else:267 returnx,y268
269 defsetMouseHandler(self, func):270 self._mouseCallback =func271
272 def_onClick(self, e):273 self.mouseX =e.x274 self.mouseY =e.y275 ifself._mouseCallback:276 self._mouseCallback(Point(e.x, e.y))277
278 classTransform:279 """Internal class for 2-D coordinate transformations"""
280
281 def __init__(self, w, h, xlow, ylow, xhigh, yhigh):282 #w, h are width and height of window
283 #(xlow,ylow) coordinates of lower-left [raw (0,h-1)]
284 #(xhigh,yhigh) coordinates of upper-right [raw (w-1,0)]
285 xspan = (xhigh-xlow)286 yspan = (yhigh-ylow)287 self.xbase =xlow288 self.ybase =yhigh289 self.xscale = xspan/float(w-1)290 self.yscale = yspan/float(h-1)291
292 defscreen(self,x,y):293 #Returns x,y in screen (actually window) coordinates
294 xs = (x-self.xbase) /self.xscale295 ys = (self.ybase-y) /self.yscale296 return int(xs+0.5),int(ys+0.5)297
298 defworld(self,xs,ys):299 #Returns xs,ys in world coordinates
300 x = xs*self.xscale +self.xbase301 y = self.ybase - ys*self.yscale302 returnx,y303 #Default values for various item configuration options. Only a subset of
304 #keys may be present in the configuration dictionary for a given item
305 DEFAULT_CONFIG = {"fill":"",306 "outline":"black",307 "width":"1",308 "arrow":"none",309 "text":"",310 "justify":"center",311 "font": ("helvetica", 12, "normal")}312 classGraphicsObject:313 """Generic base class for all of the drawable objects"""
314 #A subclass of GraphicsObject should override _draw and
315 #and _move methods.
316
317 def __init__(self, options):318 #options is a list of strings indicating which options are
319 #legal for this object.
320
321 #When an object is drawn, canvas is set to the GraphWin(canvas)
322 #object where it is drawn and id is the TK identifier of the
323 #drawn shape.
324 self.canvas =None325 self.id =None326 #config is the dictionary of configuration options for the widget.
327 config ={}328 for option inoptions:329 config[option] =DEFAULT_CONFIG[option]330 self.config =config331
332 defsetFill(self, color):333 """Set interior color to color"""
334 self._reconfig("fill", color)335
336 defsetOutline(self, color):337 """Set outline color to color"""
338 self._reconfig("outline", color)339
340 defsetWidth(self, width):341 """Set line weight to width"""
342 self._reconfig("width", width)343 defdraw(self, graphwin):344 """Draw the object in graphwin, which should be a GraphWin345 object. A GraphicsObject may only be drawn into one346 window. Raises an error if attempt made to draw an object that347 is already visible."""
348 if self.canvas and not self.canvas.isClosed(): raiseGraphicsError(OBJ_ALREADY_DRAWN)349 if graphwin.isClosed(): raise GraphicsError("Can't draw to closed window")350 self.canvas =graphwin351 self.id =self._draw(graphwin, self.config)352 ifgraphwin.autoflush:353 _root.update()354
355 defundraw(self):356 """Undraw the object (i.e. hide it). Returns silently if the357 object is not currently drawn."""
358
359 if not self.canvas: return
360 if notself.canvas.isClosed():361 self.canvas.delete(self.id)362 ifself.canvas.autoflush:363 _root.update()364 self.canvas =None365 self.id =None366 defmove(self, dx, dy):367 """move object dx units in x direction and dy units in y368 direction"""
369
370 self._move(dx,dy)371 canvas =self.canvas372 if canvas and notcanvas.isClosed():373 trans =canvas.trans374 iftrans:375 x = dx/trans.xscale376 y = -dy /trans.yscale377 else:378 x =dx379 y =dy380 self.canvas.move(self.id, x, y)381 ifcanvas.autoflush:382 _root.update()383
384 def_reconfig(self, option, setting):385 #Internal method for changing configuration of the object
386 #Raises an error if the option does not exist in the config
387 #dictionary for this object
388 if option not inself.config:389 raiseGraphicsError(UNSUPPORTED_METHOD)390 options =self.config391 options[option] =setting392 if self.canvas and notself.canvas.isClosed():393 self.canvas.itemconfig(self.id, options)394 ifself.canvas.autoflush:395 _root.update()396 def_draw(self, canvas, options):397 """draws appropriate figure on canvas with options provided398 Returns Tk id of item drawn"""
399 pass #must override in subclass
400 def_move(self, dx, dy):401 """updates internal state of object to move it dx,dy units"""
402 pass #must override in subclass
403
404 classPoint(GraphicsObject):405 def __init__(self, x, y):406 GraphicsObject.__init__(self, ["outline", "fill"])407 self.setFill =self.setOutline408 self.x =x409 self.y =y410
411 def_draw(self, canvas, options):412 x,y =canvas.toScreen(self.x,self.y)413 return canvas.create_rectangle(x,y,x+1,y+1,options)414
415 def_move(self, dx, dy):416 self.x = self.x +dx417 self.y = self.y +dy418
419 defclone(self):420 other =Point(self.x,self.y)421 other.config =self.config.copy()422 returnother423
424 def getX(self): returnself.x425 def getY(self): returnself.y426 class_BBox(GraphicsObject):427 #Internal base class for objects represented by bounding box
428 #(opposite corners) Line segment is a degenerate case.
429
430 def __init__(self, p1, p2, options=["outline","width","fill"]):431 GraphicsObject.__init__(self, options)432 self.p1 =p1.clone()433 self.p2 =p2.clone()434 def_move(self, dx, dy):435 self.p1.x = self.p1.x +dx436 self.p1.y = self.p1.y +dy437 self.p2.x = self.p2.x +dx438 self.p2.y = self.p2.y +dy439
440 def getP1(self): returnself.p1.clone()441 def getP2(self): returnself.p2.clone()442
443 defgetCenter(self):444 p1 =self.p1445 p2 =self.p2446 return Point((p1.x+p2.x)/2.0, (p1.y+p2.y)/2.0)447
448 classRectangle(_BBox):449
450 def __init__(self, p1, p2):451 _BBox.__init__(self, p1, p2)452
453 def_draw(self, canvas, options):454 p1 =self.p1455 p2 =self.p2456 x1,y1 =canvas.toScreen(p1.x,p1.y)457 x2,y2 =canvas.toScreen(p2.x,p2.y)458 returncanvas.create_rectangle(x1,y1,x2,y2,options)459
460 defclone(self):461 other =Rectangle(self.p1, self.p2)462 other.config =self.config.copy()463 returnother464
465 classOval(_BBox):466
467 def __init__(self, p1, p2):468 _BBox.__init__(self, p1, p2)469
470 defclone(self):471 other =Oval(self.p1, self.p2)472 other.config =self.config.copy()473 returnother474
475 def_draw(self, canvas, options):476 p1 =self.p1477 p2 =self.p2478 x1,y1 =canvas.toScreen(p1.x,p1.y)479 x2,y2 =canvas.toScreen(p2.x,p2.y)480 returncanvas.create_oval(x1,y1,x2,y2,options)481
482 classCircle(Oval):483
484 def __init__(self, center, radius):485 p1 = Point(center.x-radius, center.y-radius)486 p2 = Point(center.x+radius, center.y+radius)487 Oval.__init__(self, p1, p2)488 self.radius =radius489
490 defclone(self):491 other =Circle(self.getCenter(), self.radius)492 other.config =self.config.copy()493 returnother494
495 defgetRadius(self):496 returnself.radius497
498 classLine(_BBox):499
500 def __init__(self, p1, p2):501 _BBox.__init__(self, p1, p2, ["arrow","fill","width"])502 self.setFill(DEFAULT_CONFIG['outline'])503 self.setOutline =self.setFill504
505 defclone(self):506 other =Line(self.p1, self.p2)507 other.config =self.config.copy()508 returnother509
510 def_draw(self, canvas, options):511 p1 =self.p1512 p2 =self.p2513 x1,y1 =canvas.toScreen(p1.x,p1.y)514 x2,y2 =canvas.toScreen(p2.x,p2.y)515 returncanvas.create_line(x1,y1,x2,y2,options)516
517 defsetArrow(self, option):518 if not option in ["first","last","both","none"]:519 raiseGraphicsError(BAD_OPTION)520 self._reconfig("arrow", option)521
522 classPolygon(GraphicsObject):523
524 def __init__(self, *points):525 #if points passed as a list, extract it
526 if len(points) == 1 and type(points[0]) ==type([]):527 points =points[0]528 self.points =list(map(Point.clone, points))529 GraphicsObject.__init__(self, ["outline", "width", "fill"])530
531 defclone(self):532 other = Polygon(*self.points)533 other.config =self.config.copy()534 returnother535 defgetPoints(self):536 returnlist(map(Point.clone, self.points))537 def_move(self, dx, dy):538 for p inself.points:539 p.move(dx,dy)540
541 def_draw(self, canvas, options):542 args =[canvas]543 for p inself.points:544 x,y =canvas.toScreen(p.x,p.y)545 args.append(x)546 args.append(y)547 args.append(options)548 return GraphWin.create_polygon(*args)549 classText(GraphicsObject):550
551 def __init__(self, p, text):552 GraphicsObject.__init__(self, ["justify","fill","text","font"])553 self.setText(text)554 self.anchor =p.clone()555 self.setFill(DEFAULT_CONFIG['outline'])556 self.setOutline =self.setFill557
558 def_draw(self, canvas, options):559 p =self.anchor560 x,y =canvas.toScreen(p.x,p.y)561 returncanvas.create_text(x,y,options)562
563 def_move(self, dx, dy):564 self.anchor.move(dx,dy)565
566 defclone(self):567 other = Text(self.anchor, self.config['text'])568 other.config =self.config.copy()569 returnother570 defsetText(self,text):571 self._reconfig("text", text)572
573 defgetText(self):574 return self.config["text"]575
576 defgetAnchor(self):577 returnself.anchor.clone()578 defsetFace(self, face):579 if face in ['helvetica','arial','courier','times roman']:580 f,s,b = self.config['font']581 self._reconfig("font",(face,s,b))582 else:583 raiseGraphicsError(BAD_OPTION)584 defsetSize(self, size):585 if 5 <= size <= 36:586 f,s,b = self.config['font']587 self._reconfig("font", (f,size,b))588 else:589 raiseGraphicsError(BAD_OPTION)590 defsetStyle(self, style):591 if style in ['bold','normal','italic', 'bold italic']:592 f,s,b = self.config['font']593 self._reconfig("font", (f,s,style))594 else:595 raiseGraphicsError(BAD_OPTION)596 defsetTextColor(self, color):597 self.setFill(color)598 classEntry(GraphicsObject):599 def __init__(self, p, width):600 GraphicsObject.__init__(self, [])601 self.anchor =p.clone()602 #print self.anchor
603 self.width =width604 self.text =tk.StringVar(_root)605 self.text.set("")606 self.fill = "gray"
607 self.color = "black"
608 self.font = DEFAULT_CONFIG['font']609 self.entry =None610 def_draw(self, canvas, options):611 p =self.anchor612 x,y =canvas.toScreen(p.x,p.y)613 frm =tk.Frame(canvas.master)614 self.entry =tk.Entry(frm,615 width=self.width,616 textvariable=self.text,617 bg =self.fill,618 fg =self.color,619 font=self.font)620 self.entry.pack()621 #self.setFill(self.fill)
622 return canvas.create_window(x,y,window=frm)623 defgetText(self):624 returnself.text.get()625 def_move(self, dx, dy):626 self.anchor.move(dx,dy)627 defgetAnchor(self):628 returnself.anchor.clone()629 defclone(self):630 other =Entry(self.anchor, self.width)631 other.config =self.config.copy()632 other.text =tk.StringVar()633 other.text.set(self.text.get())634 other.fill =self.fill635 returnother636 defsetText(self, t):637 self.text.set(t)638
639 defsetFill(self, color):640 self.fill =color641 ifself.entry:642 self.entry.config(bg=color)643
644 def_setFontComponent(self, which, value):645 font =list(self.font)646 font[which] =value647 self.font =tuple(font)648 ifself.entry:649 self.entry.config(font=self.font)650 defsetFace(self, face):651 if face in ['helvetica','arial','courier','times roman']:652 self._setFontComponent(0, face)653 else:654 raiseGraphicsError(BAD_OPTION)655 defsetSize(self, size):656 if 5 <= size <= 36:657 self._setFontComponent(1,size)658 else:659 raiseGraphicsError(BAD_OPTION)660 defsetStyle(self, style):661 if style in ['bold','normal','italic', 'bold italic']:662 self._setFontComponent(2,style)663 else:664 raiseGraphicsError(BAD_OPTION)665 defsetTextColor(self, color):666 self.color=color667 ifself.entry:668 self.entry.config(fg=color)669 classImage(GraphicsObject):670 idCount =0671 imageCache = {} #tk photoimages go here to avoid GC while drawn
672
673 def __init__(self, p, *pixmap):674 GraphicsObject.__init__(self, [])675 self.anchor =p.clone()676 self.imageId =Image.idCount677 Image.idCount = Image.idCount + 1
678 if len(pixmap) == 1: #file name provided
679 self.img = tk.PhotoImage(file=pixmap[0], master=_root)680 else: #width and height provided
681 width, height =pixmap682 self.img = tk.PhotoImage(master=_root, width=width, height=height)683
684 def_draw(self, canvas, options):685 p =self.anchor686 x,y =canvas.toScreen(p.x,p.y)687 self.imageCache[self.imageId] = self.img #save a reference
688 return canvas.create_image(x,y,image=self.img)689
690 def_move(self, dx, dy):691 self.anchor.move(dx,dy)692
693 defundraw(self):694 del self.imageCache[self.imageId] #allow gc of tk photoimage
695 GraphicsObject.undraw(self)696 defgetAnchor(self):697 returnself.anchor.clone()698
699 defclone(self):700 other =Image(Point(0,0), 0, 0)701 other.img =self.img.copy()702 other.anchor =self.anchor.clone()703 other.config =self.config.copy()704 returnother705 defgetWidth(self):706 """Returns the width of the image in pixels"""
707 returnself.img.width()708 defgetHeight(self):709 """Returns the height of the image in pixels"""
710 returnself.img.height()711 defgetPixel(self, x, y):712 """Returns a list [r,g,b] with the RGB color values for pixel (x,y)713 r,g,b are in range(256)714 """
715
716 value =self.img.get(x,y)717 if type(value) ==type(0):718 return[value, value, value]719 else:720 returnlist(map(int, value.split()))721 defsetPixel(self, x, y, color):722 """Sets pixel (x,y) to the given color723
724 """
725 self.img.put("{" + color +"}", (x, y))726
727 defsave(self, filename):728 """Saves the pixmap image to filename.729 The format for the save image is determined from the filname extension.730 """
731
732 path, name =os.path.split(filename)733 ext = name.split(".")[-1]734 self.img.write( filename, format=ext)735
736 defcolor_rgb(r,g,b):737 """r,g,b are intensities of red, green, and blue in range(256)738 Returns color specifier string for the resulting color"""
739 return "#%02x%02x%02x" %(r,g,b)740 deftest():741 win =GraphWin()742 win.setCoords(0,0,10,10)743 t = Text(Point(5,5), "Centered Text")744 t.draw(win)745 p = Polygon(Point(1,1), Point(5,3), Point(2,7))746 p.draw(win)747 e = Entry(Point(5,6), 10)748 e.draw(win)749 win.getMouse()750 p.setFill("red")751 p.setOutline("blue")752 p.setWidth(2)753 s = ""
754 for pt inp.getPoints():755 s = s + "(%0.1f,%0.1f)" %(pt.getX(), pt.getY())756 t.setText(e.getText())757 e.setFill("green")758 e.setText("Spam!")759 e.move(2,0)760 win.getMouse()761 p.move(2,3)762 s = ""
763 for pt inp.getPoints():764 s = s + "(%0.1f,%0.1f)" %(pt.getX(), pt.getY())765 t.setText(s)766 win.getMouse()767 p.undraw()768 e.undraw()769 t.setStyle("bold")770 win.getMouse()771 t.setStyle("normal")772 win.getMouse()773 t.setStyle("italic")774 win.getMouse()775 t.setStyle("bold italic")776 win.getMouse()777 t.setSize(14)778 win.getMouse()779 t.setFace("arial")780 t.setSize(20)781 win.getMouse()782 win.close()783 if __name__ == "__main__":784 test()