2 # turtle.py: a Tkinter based turtle graphics module for Python
3 # Version 1.1b - 4. 5. 2009
5 # Copyright (C) 2006 - 2010 Gregor Lingl
8 # This software is provided 'as-is', without any express or implied
9 # warranty. In no event will the authors be held liable for any damages
10 # arising from the use of this software.
12 # Permission is granted to anyone to use this software for any purpose,
13 # including commercial applications, and to alter it and redistribute it
14 # freely, subject to the following restrictions:
16 # 1. The origin of this software must not be misrepresented; you must not
17 # claim that you wrote the original software. If you use this software
18 # in a product, an acknowledgment in the product documentation would be
19 # appreciated but is not required.
20 # 2. Altered source versions must be plainly marked as such, and must not be
21 # misrepresented as being the original software.
22 # 3. This notice may not be removed or altered from any source distribution.
26 Turtle graphics is a popular way for introducing programming to
27 kids. It was part of the original Logo programming language developed
28 by Wally Feurzig and Seymour Papert in 1966.
30 Imagine a robotic turtle starting at (0, 0) in the x-y plane. Give it
31 the command turtle.forward(15), and it moves (on-screen!) 15 pixels in
32 the direction it is facing, drawing a line as it moves. Give it the
33 command turtle.left(25), and it rotates in-place 25 degrees clockwise.
35 By combining together these and similar commands, intricate shapes and
36 pictures can easily be drawn.
40 This module is an extended reimplementation of turtle.py from the
41 Python standard distribution up to Python 2.5. (See: http://www.python.org)
43 It tries to keep the merits of turtle.py and to be (nearly) 100%
44 compatible with it. This means in the first place to enable the
45 learning programmer to use all the commands, classes and methods
46 interactively when using the module from within IDLE run with
49 Roughly it has the following features added:
51 - Better animation of the turtle movements, especially of turning the
52 turtle. So the turtles can more easily be used as a visual feedback
53 instrument by the (beginning) programmer.
55 - Different turtle shapes, gif-images as turtle shapes, user defined
56 and user controllable turtle shapes, among them compound
57 (multicolored) shapes. Turtle shapes can be stretched and tilted, which
58 makes turtles very versatile geometrical objects.
60 - Fine control over turtle movement and screen updates via delay(),
61 and enhanced tracer() and speed() methods.
63 - Aliases for the most commonly used commands, like fd for forward etc.,
64 following the early Logo traditions. This reduces the boring work of
65 typing long sequences of commands, which often occur in a natural way
66 when kids try to program fancy pictures on their first encounter with
69 - Turtles now have an undo()-method with configurable undo-buffer.
71 - Some simple commands/methods for creating event driven programs
72 (mouse-, key-, timer-events). Especially useful for programming games.
74 - A scrollable Canvas class. The default scrollable Canvas can be
75 extended interactively as needed while playing around with the turtle(s).
77 - A TurtleScreen class with methods controlling background color or
78 background image, window and canvas size and other properties of the
81 - There is a method, setworldcoordinates(), to install a user defined
82 coordinate-system for the TurtleScreen.
84 - The implementation uses a 2-vector class named Vec2D, derived from tuple.
85 This class is public, so it can be imported by the application programmer,
86 which makes certain types of computations very natural and compact.
88 - Appearance of the TurtleScreen and the Turtles at startup/import can be
89 configured by means of a turtle.cfg configuration file.
90 The default configuration mimics the appearance of the old turtle module.
92 - If configured appropriately the module reads in docstrings from a docstring
93 dictionary in some different language, supplied separately and replaces
94 the English ones by those read in. There is a utility function
95 write_docstringdict() to write a dictionary with the original (English)
96 docstrings to disc, so it can serve as a template for translations.
98 Behind the scenes there are some features included with possible
99 extensions in in mind. These will be commented and documented elsewhere.
103 _ver
= "turtle 1.1b- - for Python 3.1 - 4. 5. 2009"
113 from os
.path
import isfile
, split
, join
114 from copy
import deepcopy
115 from tkinter
import simpledialog
117 _tg_classes
= ['ScrolledCanvas', 'TurtleScreen', 'Screen',
118 'RawTurtle', 'Turtle', 'RawPen', 'Pen', 'Shape', 'Vec2D']
119 _tg_screen_functions
= ['addshape', 'bgcolor', 'bgpic', 'bye',
120 'clearscreen', 'colormode', 'delay', 'exitonclick', 'getcanvas',
121 'getshapes', 'listen', 'mainloop', 'mode', 'numinput',
122 'onkey', 'onkeypress', 'onkeyrelease', 'onscreenclick', 'ontimer',
123 'register_shape', 'resetscreen', 'screensize', 'setup',
124 'setworldcoordinates', 'textinput', 'title', 'tracer', 'turtles', 'update',
125 'window_height', 'window_width']
126 _tg_turtle_functions
= ['back', 'backward', 'begin_fill', 'begin_poly', 'bk',
127 'circle', 'clear', 'clearstamp', 'clearstamps', 'clone', 'color',
128 'degrees', 'distance', 'dot', 'down', 'end_fill', 'end_poly', 'fd',
129 'fillcolor', 'filling', 'forward', 'get_poly', 'getpen', 'getscreen', 'get_shapepoly',
130 'getturtle', 'goto', 'heading', 'hideturtle', 'home', 'ht', 'isdown',
131 'isvisible', 'left', 'lt', 'onclick', 'ondrag', 'onrelease', 'pd',
132 'pen', 'pencolor', 'pendown', 'pensize', 'penup', 'pos', 'position',
133 'pu', 'radians', 'right', 'reset', 'resizemode', 'rt',
134 'seth', 'setheading', 'setpos', 'setposition', 'settiltangle',
135 'setundobuffer', 'setx', 'sety', 'shape', 'shapesize', 'shapetransform', 'shearfactor', 'showturtle',
136 'speed', 'st', 'stamp', 'tilt', 'tiltangle', 'towards',
137 'turtlesize', 'undo', 'undobufferentries', 'up', 'width',
138 'write', 'xcor', 'ycor']
139 _tg_utilities
= ['write_docstringdict', 'done']
141 __all__
= (_tg_classes
+ _tg_screen_functions
+ _tg_turtle_functions
+
142 _tg_utilities
) # + _math_functions)
144 _alias_list
= ['addshape', 'backward', 'bk', 'fd', 'ht', 'lt', 'pd', 'pos',
145 'pu', 'rt', 'seth', 'setpos', 'setposition', 'st',
146 'turtlesize', 'up', 'width']
148 _CFG
= {"width" : 0.5, # Screen
154 "mode": "standard", # TurtleScreen
157 "undobuffersize": 1000, # RawTurtle
159 "pencolor" : "black",
160 "fillcolor" : "black",
161 "resizemode" : "noresize",
163 "language": "english", # docstrings
164 "exampleturtle": "turtle",
165 "examplescreen": "screen",
166 "title": "Python Turtle Graphics",
170 def config_dict(filename
):
171 """Convert content of config-file into dictionary."""
172 f
= open(filename
, "r")
173 cfglines
= f
.readlines()
176 for line
in cfglines
:
178 if not line
or line
.startswith("#"):
181 key
, value
= line
.split("=")
183 print("Bad line in config-file %s:\n%s" % (filename
,line
))
186 value
= value
.strip()
187 if value
in ["True", "False", "None", "''", '""']:
196 pass # value need not be converted
200 def readconfig(cfgdict
):
201 """Read config-files, change configuration-dict accordingly.
203 If there is a turtle.cfg file in the current working directory,
204 read it from there. If this contains an importconfig-value,
205 say 'myway', construct filename turtle_mayway.cfg else use
206 turtle.cfg and read it from the import-directory, where
207 turtle.py is located.
208 Update configuration dictionary first according to config-file,
209 in the import directory, then according to config-file in the
210 current working directory.
211 If no config-file is found, the default configuration is used.
213 default_cfg
= "turtle.cfg"
216 if isfile(default_cfg
):
217 cfgdict1
= config_dict(default_cfg
)
218 if "importconfig" in cfgdict1
:
219 default_cfg
= "turtle_%s.cfg" % cfgdict1
["importconfig"]
221 head
, tail
= split(__file__
)
222 cfg_file2
= join(head
, default_cfg
)
225 if isfile(cfg_file2
):
226 cfgdict2
= config_dict(cfg_file2
)
227 _CFG
.update(cfgdict2
)
228 _CFG
.update(cfgdict1
)
233 print ("No configfile read, reason unknown")
237 """A 2 dimensional vector class, used as a helper class
238 for implementing turtle graphics.
239 May be useful for turtle graphics programs also.
240 Derived from tuple, so a vector is a tuple!
242 Provides (for a, b vectors, k number):
244 a-b vector subtraction
246 k*a and a*k multiplication with scalar
247 |a| absolute value of a
248 a.rotate(angle) rotation
250 def __new__(cls
, x
, y
):
251 return tuple.__new
__(cls
, (x
, y
))
252 def __add__(self
, other
):
253 return Vec2D(self
[0]+other
[0], self
[1]+other
[1])
254 def __mul__(self
, other
):
255 if isinstance(other
, Vec2D
):
256 return self
[0]*other
[0]+self
[1]*other
[1]
257 return Vec2D(self
[0]*other
, self
[1]*other
)
258 def __rmul__(self
, other
):
259 if isinstance(other
, int) or isinstance(other
, float):
260 return Vec2D(self
[0]*other
, self
[1]*other
)
261 def __sub__(self
, other
):
262 return Vec2D(self
[0]-other
[0], self
[1]-other
[1])
264 return Vec2D(-self
[0], -self
[1])
266 return (self
[0]**2 + self
[1]**2)**0.5
267 def rotate(self
, angle
):
268 """rotate self counterclockwise by angle
270 perp
= Vec2D(-self
[1], self
[0])
271 angle
= angle
* math
.pi
/ 180.0
272 c
, s
= math
.cos(angle
), math
.sin(angle
)
273 return Vec2D(self
[0]*c
+perp
[0]*s
, self
[1]*c
+perp
[1]*s
)
274 def __getnewargs__(self
):
275 return (self
[0], self
[1])
277 return "(%.2f,%.2f)" % self
280 ##############################################################################
281 ### From here up to line : Tkinter - Interface for turtle.py ###
282 ### May be replaced by an interface to some different graphics toolkit ###
283 ##############################################################################
285 ## helper functions for Scrolled Canvas, to forward Canvas-methods
286 ## to ScrolledCanvas class
288 def __methodDict(cls
, _dict
):
289 """helper function for Scrolled Canvas"""
290 baseList
= list(cls
.__bases
__)
292 for _super
in baseList
:
293 __methodDict(_super
, _dict
)
294 for key
, value
in cls
.__dict
__.items():
295 if type(value
) == types
.FunctionType
:
299 """helper function for Scrolled Canvas"""
301 __methodDict(cls
, _dict
)
305 'def %(method)s(self, *args, **kw): return ' +
306 'self.%(attribute)s.%(method)s(*args, **kw)')
308 def __forwardmethods(fromClass
, toClass
, toPart
, exclude
= ()):
311 __methodDict(toClass
, _dict_1
)
313 mfc
= __methods(fromClass
)
314 for ex
in _dict_1
.keys():
315 if ex
[:1] == '_' or ex
[-1:] == '_' or ex
in exclude
or ex
in mfc
:
318 _dict
[ex
] = _dict_1
[ex
]
320 for method
, func
in _dict
.items():
321 d
= {'method': method
, 'func': func
}
322 if isinstance(toPart
, str):
324 __stringBody
% {'method' : method
, 'attribute' : toPart
}
326 setattr(fromClass
, method
, d
[method
]) ### NEWU!
329 class ScrolledCanvas(TK
.Frame
):
330 """Modeled after the scrolled canvas class from Grayons's Tkinter book.
332 Used as the default canvas, which pops up automatically when
333 using turtle graphics functions or the Turtle class.
335 def __init__(self
, master
, width
=500, height
=350,
336 canvwidth
=600, canvheight
=500):
337 TK
.Frame
.__init
__(self
, master
, width
=width
, height
=height
)
338 self
._rootwindow
= self
.winfo_toplevel()
339 self
.width
, self
.height
= width
, height
340 self
.canvwidth
, self
.canvheight
= canvwidth
, canvheight
342 self
._canvas
= TK
.Canvas(master
, width
=width
, height
=height
,
343 bg
=self
.bg
, relief
=TK
.SUNKEN
, borderwidth
=2)
344 self
.hscroll
= TK
.Scrollbar(master
, command
=self
._canvas
.xview
,
345 orient
=TK
.HORIZONTAL
)
346 self
.vscroll
= TK
.Scrollbar(master
, command
=self
._canvas
.yview
)
347 self
._canvas
.configure(xscrollcommand
=self
.hscroll
.set,
348 yscrollcommand
=self
.vscroll
.set)
349 self
.rowconfigure(0, weight
=1, minsize
=0)
350 self
.columnconfigure(0, weight
=1, minsize
=0)
351 self
._canvas
.grid(padx
=1, in_
= self
, pady
=1, row
=0,
352 column
=0, rowspan
=1, columnspan
=1, sticky
='news')
353 self
.vscroll
.grid(padx
=1, in_
= self
, pady
=1, row
=0,
354 column
=1, rowspan
=1, columnspan
=1, sticky
='news')
355 self
.hscroll
.grid(padx
=1, in_
= self
, pady
=1, row
=1,
356 column
=0, rowspan
=1, columnspan
=1, sticky
='news')
358 self
._rootwindow
.bind('<Configure>', self
.onResize
)
360 def reset(self
, canvwidth
=None, canvheight
=None, bg
= None):
361 """Adjust canvas and scrollbars according to given canvas size."""
363 self
.canvwidth
= canvwidth
365 self
.canvheight
= canvheight
368 self
._canvas
.config(bg
=bg
,
369 scrollregion
=(-self
.canvwidth
//2, -self
.canvheight
//2,
370 self
.canvwidth
//2, self
.canvheight
//2))
371 self
._canvas
.xview_moveto(0.5*(self
.canvwidth
- self
.width
+ 30) /
373 self
._canvas
.yview_moveto(0.5*(self
.canvheight
- self
.height
+ 30) /
378 def adjustScrolls(self
):
379 """ Adjust scrollbars according to window- and canvas-size.
381 cwidth
= self
._canvas
.winfo_width()
382 cheight
= self
._canvas
.winfo_height()
383 self
._canvas
.xview_moveto(0.5*(self
.canvwidth
-cwidth
)/self
.canvwidth
)
384 self
._canvas
.yview_moveto(0.5*(self
.canvheight
-cheight
)/self
.canvheight
)
385 if cwidth
< self
.canvwidth
or cheight
< self
.canvheight
:
386 self
.hscroll
.grid(padx
=1, in_
= self
, pady
=1, row
=1,
387 column
=0, rowspan
=1, columnspan
=1, sticky
='news')
388 self
.vscroll
.grid(padx
=1, in_
= self
, pady
=1, row
=0,
389 column
=1, rowspan
=1, columnspan
=1, sticky
='news')
391 self
.hscroll
.grid_forget()
392 self
.vscroll
.grid_forget()
394 def onResize(self
, event
):
395 """self-explanatory"""
398 def bbox(self
, *args
):
399 """ 'forward' method, which canvas itself has inherited...
401 return self
._canvas
.bbox(*args
)
403 def cget(self
, *args
, **kwargs
):
404 """ 'forward' method, which canvas itself has inherited...
406 return self
._canvas
.cget(*args
, **kwargs
)
408 def config(self
, *args
, **kwargs
):
409 """ 'forward' method, which canvas itself has inherited...
411 self
._canvas
.config(*args
, **kwargs
)
413 def bind(self
, *args
, **kwargs
):
414 """ 'forward' method, which canvas itself has inherited...
416 self
._canvas
.bind(*args
, **kwargs
)
418 def unbind(self
, *args
, **kwargs
):
419 """ 'forward' method, which canvas itself has inherited...
421 self
._canvas
.unbind(*args
, **kwargs
)
423 def focus_force(self
):
424 """ 'forward' method, which canvas itself has inherited...
426 self
._canvas
.focus_force()
428 __forwardmethods(ScrolledCanvas
, TK
.Canvas
, '_canvas')
432 """Root class for Screen based on Tkinter."""
436 def setupcanvas(self
, width
, height
, cwidth
, cheight
):
437 self
._canvas
= ScrolledCanvas(self
, width
, height
, cwidth
, cheight
)
438 self
._canvas
.pack(expand
=1, fill
="both")
440 def _getcanvas(self
):
443 def set_geometry(self
, width
, height
, startx
, starty
):
444 self
.geometry("%dx%d%+d%+d"%(width
, height
, startx
, starty
))
446 def ondestroy(self
, destroy
):
447 self
.wm_protocol("WM_DELETE_WINDOW", destroy
)
450 return self
.winfo_screenwidth()
452 def win_height(self
):
453 return self
.winfo_screenheight()
458 class TurtleScreenBase(object):
459 """Provide the basic graphics functionality.
460 Interface between Tkinter and turtle.py.
462 To port turtle.py to some different graphics toolkit
463 a corresponding TurtleScreenBase class has to be implemented.
468 """return a blank image object
470 img
= TK
.PhotoImage(width
=1, height
=1)
475 def _image(filename
):
476 """return an image object containing the
477 imagedata from a gif-file named filename.
479 return TK
.PhotoImage(file=filename
)
481 def __init__(self
, cv
):
483 if isinstance(cv
, ScrolledCanvas
):
484 w
= self
.cv
.canvwidth
485 h
= self
.cv
.canvheight
486 else: # expected: ordinary TK.Canvas
487 w
= int(self
.cv
.cget("width"))
488 h
= int(self
.cv
.cget("height"))
489 self
.cv
.config(scrollregion
= (-w
//2, -h
//2, w
//2, h
//2 ))
492 self
.xscale
= self
.yscale
= 1.0
494 def _createpoly(self
):
495 """Create an invisible polygon item on canvas self.cv)
497 return self
.cv
.create_polygon((0, 0, 0, 0, 0, 0), fill
="", outline
="")
499 def _drawpoly(self
, polyitem
, coordlist
, fill
=None,
500 outline
=None, width
=None, top
=False):
501 """Configure polygonitem polyitem according to provided
503 coordlist is sequence of coordinates
504 fill is filling color
505 outline is outline color
506 top is a boolean value, which specifies if polyitem
507 will be put on top of the canvas' displaylist so it
508 will not be covered by other items.
511 for x
, y
in coordlist
:
512 cl
.append(x
* self
.xscale
)
513 cl
.append(-y
* self
.yscale
)
514 self
.cv
.coords(polyitem
, *cl
)
516 self
.cv
.itemconfigure(polyitem
, fill
=fill
)
517 if outline
is not None:
518 self
.cv
.itemconfigure(polyitem
, outline
=outline
)
519 if width
is not None:
520 self
.cv
.itemconfigure(polyitem
, width
=width
)
522 self
.cv
.tag_raise(polyitem
)
524 def _createline(self
):
525 """Create an invisible line item on canvas self.cv)
527 return self
.cv
.create_line(0, 0, 0, 0, fill
="", width
=2,
530 def _drawline(self
, lineitem
, coordlist
=None,
531 fill
=None, width
=None, top
=False):
532 """Configure lineitem according to provided arguments:
533 coordlist is sequence of coordinates
534 fill is drawing color
535 width is width of drawn line.
536 top is a boolean value, which specifies if polyitem
537 will be put on top of the canvas' displaylist so it
538 will not be covered by other items.
540 if coordlist
is not None:
542 for x
, y
in coordlist
:
543 cl
.append(x
* self
.xscale
)
544 cl
.append(-y
* self
.yscale
)
545 self
.cv
.coords(lineitem
, *cl
)
547 self
.cv
.itemconfigure(lineitem
, fill
=fill
)
548 if width
is not None:
549 self
.cv
.itemconfigure(lineitem
, width
=width
)
551 self
.cv
.tag_raise(lineitem
)
553 def _delete(self
, item
):
554 """Delete graphics item from canvas.
555 If item is"all" delete all graphics items.
560 """Redraw graphics items on canvas
564 def _delay(self
, delay
):
565 """Delay subsequent canvas actions for delay ms."""
568 def _iscolorstring(self
, color
):
569 """Check if the string color is a legal Tkinter color string.
572 rgb
= self
.cv
.winfo_rgb(color
)
578 def _bgcolor(self
, color
=None):
579 """Set canvas' backgroundcolor if color is not None,
580 else return backgroundcolor."""
581 if color
is not None:
582 self
.cv
.config(bg
= color
)
585 return self
.cv
.cget("bg")
587 def _write(self
, pos
, txt
, align
, font
, pencolor
):
588 """Write txt at pos in canvas with specified font
590 Return text item and x-coord of right bottom corner
591 of text's bounding box."""
595 anchor
= {"left":"sw", "center":"s", "right":"se" }
596 item
= self
.cv
.create_text(x
-1, -y
, text
= txt
, anchor
= anchor
[align
],
597 fill
= pencolor
, font
= font
)
598 x0
, y0
, x1
, y1
= self
.cv
.bbox(item
)
602 ## def _dot(self, pos, size, color):
603 ## """may be implemented for some other graphics toolkit"""
605 def _onclick(self
, item
, fun
, num
=1, add
=None):
606 """Bind fun to mouse-click event on turtle.
607 fun must be a function with two arguments, the coordinates
608 of the clicked point on the canvas.
609 num, the number of the mouse-button defaults to 1
612 self
.cv
.tag_unbind(item
, "<Button-%s>" % num
)
615 x
, y
= (self
.cv
.canvasx(event
.x
)/self
.xscale
,
616 -self
.cv
.canvasy(event
.y
)/self
.yscale
)
618 self
.cv
.tag_bind(item
, "<Button-%s>" % num
, eventfun
, add
)
620 def _onrelease(self
, item
, fun
, num
=1, add
=None):
621 """Bind fun to mouse-button-release event on turtle.
622 fun must be a function with two arguments, the coordinates
623 of the point on the canvas where mouse button is released.
624 num, the number of the mouse-button defaults to 1
626 If a turtle is clicked, first _onclick-event will be performed,
627 then _onscreensclick-event.
630 self
.cv
.tag_unbind(item
, "<Button%s-ButtonRelease>" % num
)
633 x
, y
= (self
.cv
.canvasx(event
.x
)/self
.xscale
,
634 -self
.cv
.canvasy(event
.y
)/self
.yscale
)
636 self
.cv
.tag_bind(item
, "<Button%s-ButtonRelease>" % num
,
639 def _ondrag(self
, item
, fun
, num
=1, add
=None):
640 """Bind fun to mouse-move-event (with pressed mouse button) on turtle.
641 fun must be a function with two arguments, the coordinates of the
642 actual mouse position on the canvas.
643 num, the number of the mouse-button defaults to 1
645 Every sequence of mouse-move-events on a turtle is preceded by a
646 mouse-click event on that turtle.
649 self
.cv
.tag_unbind(item
, "<Button%s-Motion>" % num
)
653 x
, y
= (self
.cv
.canvasx(event
.x
)/self
.xscale
,
654 -self
.cv
.canvasy(event
.y
)/self
.yscale
)
658 self
.cv
.tag_bind(item
, "<Button%s-Motion>" % num
, eventfun
, add
)
660 def _onscreenclick(self
, fun
, num
=1, add
=None):
661 """Bind fun to mouse-click event on canvas.
662 fun must be a function with two arguments, the coordinates
663 of the clicked point on the canvas.
664 num, the number of the mouse-button defaults to 1
666 If a turtle is clicked, first _onclick-event will be performed,
667 then _onscreensclick-event.
670 self
.cv
.unbind("<Button-%s>" % num
)
673 x
, y
= (self
.cv
.canvasx(event
.x
)/self
.xscale
,
674 -self
.cv
.canvasy(event
.y
)/self
.yscale
)
676 self
.cv
.bind("<Button-%s>" % num
, eventfun
, add
)
678 def _onkeyrelease(self
, fun
, key
):
679 """Bind fun to key-release event of key.
680 Canvas must have focus. See method listen
683 self
.cv
.unbind("<KeyRelease-%s>" % key
, None)
687 self
.cv
.bind("<KeyRelease-%s>" % key
, eventfun
)
689 def _onkeypress(self
, fun
, key
=None):
690 """If key is given, bind fun to key-press event of key.
691 Otherwise bind fun to any key-press.
692 Canvas must have focus. See method listen.
696 self
.cv
.unbind("<KeyPress>", None)
698 self
.cv
.unbind("<KeyPress-%s>" % key
, None)
703 self
.cv
.bind("<KeyPress>", eventfun
)
705 self
.cv
.bind("<KeyPress-%s>" % key
, eventfun
)
708 """Set focus on canvas (in order to collect key-events)
710 self
.cv
.focus_force()
712 def _ontimer(self
, fun
, t
):
713 """Install a timer, which calls fun after t milliseconds.
716 self
.cv
.after_idle(fun
)
718 self
.cv
.after(t
, fun
)
720 def _createimage(self
, image
):
721 """Create and return image item on canvas.
723 return self
.cv
.create_image(0, 0, image
=image
)
725 def _drawimage(self
, item
, pos
, image
):
726 """Configure image item as to draw image object
727 at position (x,y) on canvas)
730 self
.cv
.coords(item
, (x
* self
.xscale
, -y
* self
.yscale
))
731 self
.cv
.itemconfig(item
, image
=image
)
733 def _setbgpic(self
, item
, image
):
734 """Configure image item as to draw image object
735 at center of canvas. Set item to the first item
736 in the displaylist, so it will be drawn below
738 self
.cv
.itemconfig(item
, image
=image
)
739 self
.cv
.tag_lower(item
)
741 def _type(self
, item
):
742 """Return 'line' or 'polygon' or 'image' depending on
745 return self
.cv
.type(item
)
747 def _pointlist(self
, item
):
748 """returns list of coordinate-pairs of points of item
749 Example (for insiders):
750 >>> from turtle import *
751 >>> getscreen()._pointlist(getturtle().turtle._item)
752 [(0.0, 9.9999999999999982), (0.0, -9.9999999999999982),
753 (9.9999999999999982, 0.0)]
755 cl
= list(self
.cv
.coords(item
))
756 pl
= [(cl
[i
], -cl
[i
+1]) for i
in range(0, len(cl
), 2)]
759 def _setscrollregion(self
, srx1
, sry1
, srx2
, sry2
):
760 self
.cv
.config(scrollregion
=(srx1
, sry1
, srx2
, sry2
))
762 def _rescale(self
, xscalefactor
, yscalefactor
):
763 items
= self
.cv
.find_all()
765 coordinates
= list(self
.cv
.coords(item
))
768 x
, y
= coordinates
[:2]
769 newcoordlist
.append(x
* xscalefactor
)
770 newcoordlist
.append(y
* yscalefactor
)
771 coordinates
= coordinates
[2:]
772 self
.cv
.coords(item
, *newcoordlist
)
774 def _resize(self
, canvwidth
=None, canvheight
=None, bg
=None):
775 """Resize the canvas the turtles are drawing on. Does
776 not alter the drawing window.
779 if not isinstance(self
.cv
, ScrolledCanvas
):
780 return self
.canvwidth
, self
.canvheight
781 if canvwidth
is canvheight
is bg
is None:
782 return self
.cv
.canvwidth
, self
.cv
.canvheight
783 if canvwidth
is not None:
784 self
.canvwidth
= canvwidth
785 if canvheight
is not None:
786 self
.canvheight
= canvheight
787 self
.cv
.reset(canvwidth
, canvheight
, bg
)
789 def _window_size(self
):
790 """ Return the width and height of the turtle window.
792 width
= self
.cv
.winfo_width()
793 if width
<= 1: # the window isn't managed by a geometry manager
794 width
= self
.cv
['width']
795 height
= self
.cv
.winfo_height()
796 if height
<= 1: # the window isn't managed by a geometry manager
797 height
= self
.cv
['height']
801 """Starts event loop - calling Tkinter's mainloop function.
805 Must be last statement in a turtle graphics program.
806 Must NOT be used if a script is run from within IDLE in -n mode
807 (No subprocess) - for interactive use of turtle graphics.
809 Example (for a TurtleScreen instance named screen):
810 >>> screen.mainloop()
815 def textinput(self
, title
, prompt
):
816 """Pop up a dialog window for input of a string.
818 Arguments: title is the title of the dialog window,
819 prompt is a text mostly describing what information to input.
821 Return the string input
822 If the dialog is canceled, return None.
824 Example (for a TurtleScreen instance named screen):
825 >>> screen.textinput("NIM", "Name of first player:")
828 return simpledialog
.askstring(title
, prompt
)
830 def numinput(self
, title
, prompt
, default
=None, minval
=None, maxval
=None):
831 """Pop up a dialog window for input of a number.
833 Arguments: title is the title of the dialog window,
834 prompt is a text mostly describing what numerical information to input.
835 default: default value
836 minval: minimum value for imput
837 maxval: maximum value for input
839 The number input must be in the range minval .. maxval if these are
840 given. If not, a hint is issued and the dialog remains open for
841 correction. Return the number input.
842 If the dialog is canceled, return None.
844 Example (for a TurtleScreen instance named screen):
845 >>> screen.numinput("Poker", "Your stakes:", 1000, minval=10, maxval=10000)
848 return simpledialog
.askfloat(title
, prompt
, initialvalue
=default
,
849 minvalue
=minval
, maxvalue
=maxval
)
852 ##############################################################################
853 ### End of Tkinter - interface ###
854 ##############################################################################
857 class Terminator (Exception):
858 """Will be raised in TurtleScreen.update, if _RUNNING becomes False.
860 Thus stops execution of turtle graphics script. Main purpose: use in
861 in the Demo-Viewer turtle.Demo.py.
866 class TurtleGraphicsError(Exception):
867 """Some TurtleGraphics Error
872 """Data structure modeling shapes.
874 attribute _type is one of "polygon", "image", "compound"
875 attribute _data is - depending on _type a poygon-tuple,
876 an image or a list constructed using the addcomponent method.
878 def __init__(self
, type_
, data
=None):
880 if type_
== "polygon":
881 if isinstance(data
, list):
883 elif type_
== "image":
884 if isinstance(data
, str):
885 if data
.lower().endswith(".gif") and isfile(data
):
886 data
= TurtleScreen
._image
(data
)
887 # else data assumed to be Photoimage
888 elif type_
== "compound":
891 raise TurtleGraphicsError("There is no shape type %s" % type_
)
894 def addcomponent(self
, poly
, fill
, outline
=None):
895 """Add component to a shape of type compound.
897 Arguments: poly is a polygon, i. e. a tuple of number pairs.
898 fill is the fillcolor of the component,
899 outline is the outline color of the component.
901 call (for a Shapeobject namend s):
902 -- s.addcomponent(((0,0), (10,10), (-10,10)), "red", "blue")
905 >>> poly = ((0,0),(10,-5),(0,10),(-10,-5))
906 >>> s = Shape("compound")
907 >>> s.addcomponent(poly, "red", "blue")
908 ### .. add more components and then use register_shape()
910 if self
._type
!= "compound":
911 raise TurtleGraphicsError("Cannot add component to %s Shape"
915 self
._data
.append([poly
, fill
, outline
])
918 class Tbuffer(object):
919 """Ring buffer used as undobuffer for RawTurtle objects."""
920 def __init__(self
, bufsize
=10):
921 self
.bufsize
= bufsize
922 self
.buffer = [[None]] * bufsize
924 self
.cumulate
= False
925 def reset(self
, bufsize
=None):
927 for i
in range(self
.bufsize
):
928 self
.buffer[i
] = [None]
930 self
.bufsize
= bufsize
931 self
.buffer = [[None]] * bufsize
933 def push(self
, item
):
935 if not self
.cumulate
:
936 self
.ptr
= (self
.ptr
+ 1) % self
.bufsize
937 self
.buffer[self
.ptr
] = item
939 self
.buffer[self
.ptr
].append(item
)
942 item
= self
.buffer[self
.ptr
]
946 self
.buffer[self
.ptr
] = [None]
947 self
.ptr
= (self
.ptr
- 1) % self
.bufsize
949 def nr_of_items(self
):
950 return self
.bufsize
- self
.buffer.count([None])
952 return str(self
.buffer) + " " + str(self
.ptr
)
956 class TurtleScreen(TurtleScreenBase
):
957 """Provides screen oriented methods like setbg etc.
959 Only relies upon the methods of TurtleScreenBase and NOT
960 upon components of the underlying graphics toolkit -
961 which is Tkinter in this case.
965 def __init__(self
, cv
, mode
=_CFG
["mode"],
966 colormode
=_CFG
["colormode"], delay
=_CFG
["delay"]):
968 "arrow" : Shape("polygon", ((-10,0), (10,0), (0,10))),
969 "turtle" : Shape("polygon", ((0,16), (-2,14), (-1,10), (-4,7),
970 (-7,9), (-9,8), (-6,5), (-7,1), (-5,-3), (-8,-6),
971 (-6,-8), (-4,-5), (0,-7), (4,-5), (6,-8), (8,-6),
972 (5,-3), (7,1), (6,5), (9,8), (7,9), (4,7), (1,10),
974 "circle" : Shape("polygon", ((10,0), (9.51,3.09), (8.09,5.88),
975 (5.88,8.09), (3.09,9.51), (0,10), (-3.09,9.51),
976 (-5.88,8.09), (-8.09,5.88), (-9.51,3.09), (-10,0),
977 (-9.51,-3.09), (-8.09,-5.88), (-5.88,-8.09),
978 (-3.09,-9.51), (-0.00,-10.00), (3.09,-9.51),
979 (5.88,-8.09), (8.09,-5.88), (9.51,-3.09))),
980 "square" : Shape("polygon", ((10,-10), (10,10), (-10,10),
982 "triangle" : Shape("polygon", ((10,-5.77), (0,11.55),
984 "classic": Shape("polygon", ((0,0),(-5,-9),(0,-7),(5,-9))),
985 "blank" : Shape("image", self
._blankimage
())
988 self
._bgpics
= {"nopic" : ""}
990 TurtleScreenBase
.__init
__(self
, cv
)
992 self
._delayvalue
= delay
993 self
._colormode
= _CFG
["colormode"]
998 """Delete all drawings and all turtles from the TurtleScreen.
1002 Reset empty TurtleScreen to its initial state: white background,
1003 no backgroundimage, no eventbindings and tracing on.
1005 Example (for a TurtleScreen instance named screen):
1008 Note: this method is not available as function.
1010 self
._delayvalue
= _CFG
["delay"]
1011 self
._colormode
= _CFG
["colormode"]
1013 self
._bgpic
= self
._createimage
("")
1014 self
._bgpicname
= "nopic"
1016 self
._updatecounter
= 0
1018 self
.bgcolor("white")
1020 self
.onclick(None, btn
)
1021 self
.onkeypress(None)
1022 for key
in self
._keys
[:]:
1023 self
.onkey(None, key
)
1024 self
.onkeypress(None, key
)
1027 def mode(self
, mode
=None):
1028 """Set turtle-mode ('standard', 'logo' or 'world') and perform reset.
1031 mode -- on of the strings 'standard', 'logo' or 'world'
1033 Mode 'standard' is compatible with turtle.py.
1034 Mode 'logo' is compatible with most Logo-Turtle-Graphics.
1035 Mode 'world' uses userdefined 'worldcoordinates'. *Attention*: in
1036 this mode angles appear distorted if x/y unit-ratio doesn't equal 1.
1037 If mode is not given, return the current mode.
1039 Mode Initial turtle heading positive angles
1040 ------------|-------------------------|-------------------
1041 'standard' to the right (east) counterclockwise
1042 'logo' upward (north) clockwise
1045 >>> mode('logo') # resets turtle heading to north
1052 if mode
not in ["standard", "logo", "world"]:
1053 raise TurtleGraphicsError("No turtle-graphics-mode %s" % mode
)
1055 if mode
in ["standard", "logo"]:
1056 self
._setscrollregion
(-self
.canvwidth
//2, -self
.canvheight
//2,
1057 self
.canvwidth
//2, self
.canvheight
//2)
1058 self
.xscale
= self
.yscale
= 1.0
1061 def setworldcoordinates(self
, llx
, lly
, urx
, ury
):
1062 """Set up a user defined coordinate-system.
1065 llx -- a number, x-coordinate of lower left corner of canvas
1066 lly -- a number, y-coordinate of lower left corner of canvas
1067 urx -- a number, x-coordinate of upper right corner of canvas
1068 ury -- a number, y-coordinate of upper right corner of canvas
1070 Set up user coodinat-system and switch to mode 'world' if necessary.
1071 This performs a screen.reset. If mode 'world' is already active,
1072 all drawings are redrawn according to the new coordinates.
1074 But ATTENTION: in user-defined coordinatesystems angles may appear
1075 distorted. (see Screen.mode())
1077 Example (for a TurtleScreen instance named screen):
1078 >>> screen.setworldcoordinates(-10,-0.5,50,1.5)
1079 >>> for _ in range(36):
1083 if self
.mode() != "world":
1085 xspan
= float(urx
- llx
)
1086 yspan
= float(ury
- lly
)
1087 wx
, wy
= self
._window
_size
()
1088 self
.screensize(wx
-20, wy
-20)
1089 oldxscale
, oldyscale
= self
.xscale
, self
.yscale
1090 self
.xscale
= self
.canvwidth
/ xspan
1091 self
.yscale
= self
.canvheight
/ yspan
1092 srx1
= llx
* self
.xscale
1093 sry1
= -ury
* self
.yscale
1094 srx2
= self
.canvwidth
+ srx1
1095 sry2
= self
.canvheight
+ sry1
1096 self
._setscrollregion
(srx1
, sry1
, srx2
, sry2
)
1097 self
._rescale
(self
.xscale
/oldxscale
, self
.yscale
/oldyscale
)
1100 def register_shape(self
, name
, shape
=None):
1101 """Adds a turtle shape to TurtleScreen's shapelist.
1104 (1) name is the name of a gif-file and shape is None.
1105 Installs the corresponding image shape.
1106 !! Image-shapes DO NOT rotate when turning the turtle,
1107 !! so they do not display the heading of the turtle!
1108 (2) name is an arbitrary string and shape is a tuple
1109 of pairs of coordinates. Installs the corresponding
1111 (3) name is an arbitrary string and shape is a
1112 (compound) Shape object. Installs the corresponding
1114 To use a shape, you have to issue the command shape(shapename).
1116 call: register_shape("turtle.gif")
1117 --or: register_shape("tri", ((0,0), (10,10), (-10,10)))
1119 Example (for a TurtleScreen instance named screen):
1120 >>> screen.register_shape("triangle", ((5,-3),(0,5),(-5,-3)))
1125 if name
.lower().endswith(".gif"):
1126 shape
= Shape("image", self
._image
(name
))
1128 raise TurtleGraphicsError("Bad arguments for register_shape.\n"
1129 + "Use help(register_shape)" )
1130 elif isinstance(shape
, tuple):
1131 shape
= Shape("polygon", shape
)
1132 ## else shape assumed to be Shape-instance
1133 self
._shapes
[name
] = shape
1135 def _colorstr(self
, color
):
1136 """Return color string corresponding to args.
1138 Argument may be a string or a tuple of three
1139 numbers corresponding to actual colormode,
1140 i.e. in the range 0<=n<=colormode.
1142 If the argument doesn't represent a color,
1147 if isinstance(color
, str):
1148 if self
._iscolorstring
(color
) or color
== "":
1151 raise TurtleGraphicsError("bad color string: %s" % str(color
))
1155 raise TurtleGraphicsError("bad color arguments: %s" % str(color
))
1156 if self
._colormode
== 1.0:
1157 r
, g
, b
= [round(255.0*x
) for x
in (r
, g
, b
)]
1158 if not ((0 <= r
<= 255) and (0 <= g
<= 255) and (0 <= b
<= 255)):
1159 raise TurtleGraphicsError("bad color sequence: %s" % str(color
))
1160 return "#%02x%02x%02x" % (r
, g
, b
)
1162 def _color(self
, cstr
):
1163 if not cstr
.startswith("#"):
1166 cl
= [int(cstr
[i
:i
+2], 16) for i
in (1, 3, 5)]
1167 elif len(cstr
) == 4:
1168 cl
= [16*int(cstr
[h
], 16) for h
in cstr
[1:]]
1170 raise TurtleGraphicsError("bad colorstring: %s" % cstr
)
1171 return tuple([c
* self
._colormode
/255 for c
in cl
])
1173 def colormode(self
, cmode
=None):
1174 """Return the colormode or set it to 1.0 or 255.
1177 cmode -- one of the values 1.0 or 255
1179 r, g, b values of colortriples have to be in range 0..cmode.
1181 Example (for a TurtleScreen instance named screen):
1182 >>> screen.colormode()
1184 >>> screen.colormode(255)
1185 >>> turtle.pencolor(240,160,80)
1188 return self
._colormode
1190 self
._colormode
= float(cmode
)
1192 self
._colormode
= int(cmode
)
1195 """Reset all Turtles on the Screen to their initial state.
1199 Example (for a TurtleScreen instance named screen):
1202 for turtle
in self
._turtles
:
1203 turtle
._setmode
(self
._mode
)
1207 """Return the list of turtles on the screen.
1209 Example (for a TurtleScreen instance named screen):
1210 >>> screen.turtles()
1211 [<turtle.Turtle object at 0x00E11FB0>]
1213 return self
._turtles
1215 def bgcolor(self
, *args
):
1216 """Set or return backgroundcolor of the TurtleScreen.
1218 Arguments (if given): a color string or three numbers
1219 in the range 0..colormode or a 3-tuple of such numbers.
1221 Example (for a TurtleScreen instance named screen):
1222 >>> screen.bgcolor("orange")
1223 >>> screen.bgcolor()
1225 >>> screen.bgcolor(0.5,0,0.5)
1226 >>> screen.bgcolor()
1230 color
= self
._colorstr
(args
)
1233 color
= self
._bgcolor
(color
)
1234 if color
is not None:
1235 color
= self
._color
(color
)
1238 def tracer(self
, n
=None, delay
=None):
1239 """Turns turtle animation on/off and set delay for update drawings.
1242 n -- nonnegative integer
1243 delay -- nonnegative integer
1245 If n is given, only each n-th regular screen update is really performed.
1246 (Can be used to accelerate the drawing of complex graphics.)
1247 Second arguments sets delay value (see RawTurtle.delay())
1249 Example (for a TurtleScreen instance named screen):
1250 >>> screen.tracer(8, 25)
1252 >>> for i in range(200):
1258 return self
._tracing
1259 self
._tracing
= int(n
)
1260 self
._updatecounter
= 0
1261 if delay
is not None:
1262 self
._delayvalue
= int(delay
)
1266 def delay(self
, delay
=None):
1267 """ Return or set the drawing delay in milliseconds.
1270 delay -- positive integer
1272 Example (for a TurtleScreen instance named screen):
1273 >>> screen.delay(15)
1278 return self
._delayvalue
1279 self
._delayvalue
= int(delay
)
1281 def _incrementudc(self
):
1282 "Increment upadate counter."""
1283 if not TurtleScreen._RUNNING:
1284 TurtleScreen._RUNNNING = True
1286 if self._tracing > 0:
1287 self._updatecounter += 1
1288 self._updatecounter %= self._tracing
1291 """Perform a TurtleScreen update.
1293 tracing = self._tracing
1294 self._tracing = True
1295 for t in self.turtles():
1298 self._tracing = tracing
1301 def window_width(self):
1302 """ Return the width of the turtle window.
1304 Example (for a TurtleScreen instance named screen):
1305 >>> screen.window_width()
1308 return self._window_size()[0]
1310 def window_height(self):
1311 """ Return the height of the turtle window.
1313 Example (for a TurtleScreen instance named screen):
1314 >>> screen.window_height()
1317 return self._window_size()[1]
1319 def getcanvas(self):
1320 """Return the Canvas of this TurtleScreen.
1324 Example (for a Screen instance named screen):
1325 >>> cv = screen.getcanvas()
1327 <turtle.ScrolledCanvas instance at 0x010742D8>
1331 def getshapes(self):
1332 """Return a list of names of all currently available turtle shapes.
1336 Example (for a TurtleScreen instance named screen):
1337 >>> screen.getshapes()
1338 ['arrow', 'blank', 'circle', ... , 'turtle']
1340 return sorted(self._shapes.keys())
1342 def onclick(self, fun, btn=1, add=None):
1343 """Bind fun to mouse-click event on canvas.
1346 fun -- a function with two arguments, the coordinates of the
1347 clicked point on the canvas.
1348 num -- the number of the mouse-button, defaults to 1
1350 Example (for a TurtleScreen instance named screen
1351 and a Turtle instance named turtle):
1353 >>> screen.onclick(turtle.goto)
1355 ### Subsequently clicking into the TurtleScreen will
1356 ### make the turtle move to the clicked point.
1357 >>> screen.onclick(None)
1359 ### event-binding will be removed
1361 self._onscreenclick(fun, btn, add)
1363 def onkey(self, fun, key):
1364 """Bind fun to key-release event of key.
1367 fun -- a function with no arguments
1368 key -- a string: key (e.g. "a
") or key-symbol (e.g. "space
")
1370 In order to be able to register key-events, TurtleScreen
1371 must have focus. (See method listen.)
1373 Example (for a TurtleScreen instance named screen
1374 and a Turtle instance named turtle):
1381 >>> screen.onkey(f, "Up
")
1384 ### Subsequently the turtle can be moved by
1385 ### repeatedly pressing the up-arrow key,
1386 ### consequently drawing a hexagon
1389 if key in self._keys:
1390 self._keys.remove(key)
1391 elif key not in self._keys:
1392 self._keys.append(key)
1393 self._onkeyrelease(fun, key)
1395 def onkeypress(self, fun, key=None):
1396 """Bind fun to key-press event of key if key is given,
1397 or to any key-press-event if no key is given.
1400 fun -- a function with no arguments
1401 key -- a string: key (e.g. "a
") or key-symbol (e.g. "space
")
1403 In order to be able to register key-events, TurtleScreen
1404 must have focus. (See method listen.)
1406 Example (for a TurtleScreen instance named screen
1407 and a Turtle instance named turtle):
1413 >>> screen.onkey(f, "Up
")
1416 ### Subsequently the turtle can be moved by
1417 ### repeatedly pressing the up-arrow key,
1418 ### or by keeping pressed the up-arrow key.
1419 ### consequently drawing a hexagon.
1422 if key in self._keys:
1423 self._keys.remove(key)
1424 elif key is not None and key not in self._keys:
1425 self._keys.append(key)
1426 self._onkeypress(fun, key)
1428 def listen(self, xdummy=None, ydummy=None):
1429 """Set focus on TurtleScreen (in order to collect key-events)
1432 Dummy arguments are provided in order
1433 to be able to pass listen to the onclick method.
1435 Example (for a TurtleScreen instance named screen):
1440 def ontimer(self, fun, t=0):
1441 """Install a timer, which calls fun after t milliseconds.
1444 fun -- a function with no arguments.
1447 Example (for a TurtleScreen instance named screen):
1454 screen.ontimer(f, 250)
1456 >>> f() ### makes the turtle marching around
1459 self._ontimer(fun, t)
1461 def bgpic(self, picname=None):
1462 """Set background image or return name of current backgroundimage.
1465 picname -- a string, name of a gif-file or "nopic
".
1467 If picname is a filename, set the corresponing image as background.
1468 If picname is "nopic
", delete backgroundimage, if present.
1469 If picname is None, return the filename of the current backgroundimage.
1471 Example (for a TurtleScreen instance named screen):
1474 >>> screen.bgpic("landscape
.gif
")
1479 return self._bgpicname
1480 if picname not in self._bgpics:
1481 self._bgpics[picname] = self._image(picname)
1482 self._setbgpic(self._bgpic, self._bgpics[picname])
1483 self._bgpicname = picname
1485 def screensize(self, canvwidth=None, canvheight=None, bg=None):
1486 """Resize the canvas the turtles are drawing on.
1489 canvwidth -- positive integer, new width of canvas in pixels
1490 canvheight -- positive integer, new height of canvas in pixels
1491 bg -- colorstring or color-tupel, new backgroundcolor
1492 If no arguments are given, return current (canvaswidth, canvasheight)
1494 Do not alter the drawing window. To observe hidden parts of
1495 the canvas use the scrollbars. (Can make visible those parts
1496 of a drawing, which were outside the canvas before!)
1498 Example (for a Turtle instance named turtle):
1499 >>> turtle.screensize(2000,1500)
1500 ### e. g. to search for an erroneously escaped turtle ;-)
1502 return self._resize(canvwidth, canvheight, bg)
1504 onscreenclick = onclick
1507 addshape = register_shape
1508 onkeyrelease = onkey
1510 class TNavigator(object):
1511 """Navigation part of the RawTurtle.
1512 Implements methods for turtle movement.
1514 START_ORIENTATION = {
1515 "standard
": Vec2D(1.0, 0.0),
1516 "world
" : Vec2D(1.0, 0.0),
1517 "logo
" : Vec2D(0.0, 1.0) }
1518 DEFAULT_MODE = "standard
"
1519 DEFAULT_ANGLEOFFSET = 0
1520 DEFAULT_ANGLEORIENT = 1
1522 def __init__(self, mode=DEFAULT_MODE):
1523 self._angleOffset = self.DEFAULT_ANGLEOFFSET
1524 self._angleOrient = self.DEFAULT_ANGLEORIENT
1526 self.undobuffer = None
1530 TNavigator.reset(self)
1533 """reset turtle to its initial values
1535 Will be overwritten by parent class
1537 self._position = Vec2D(0.0, 0.0)
1538 self._orient = TNavigator.START_ORIENTATION[self._mode]
1540 def _setmode(self, mode=None):
1541 """Set turtle-mode to 'standard', 'world' or 'logo'.
1545 if mode not in ["standard
", "logo
", "world
"]:
1548 if mode in ["standard
", "world
"]:
1549 self._angleOffset = 0
1550 self._angleOrient = 1
1551 else: # mode == "logo
":
1552 self._angleOffset = self._fullcircle/4.
1553 self._angleOrient = -1
1555 def _setDegreesPerAU(self, fullcircle):
1556 """Helper function for degrees() and radians()"""
1557 self._fullcircle = fullcircle
1558 self._degreesPerAU = 360/fullcircle
1559 if self._mode == "standard
":
1560 self._angleOffset = 0
1562 self._angleOffset = fullcircle/4.
1564 def degrees(self, fullcircle=360.0):
1565 """ Set angle measurement units to degrees.
1568 fullcircle - a number
1570 Set angle measurement units, i. e. set number
1571 of 'degrees' for a full circle. Dafault value is
1574 Example (for a Turtle instance named turtle):
1576 >>> turtle.heading()
1578 >>> turtle.degrees(400.0) # angle measurement in gon
1579 >>> turtle.heading()
1583 self._setDegreesPerAU(fullcircle)
1586 """ Set the angle measurement units to radians.
1590 Example (for a Turtle instance named turtle):
1591 >>> turtle.heading()
1593 >>> turtle.radians()
1594 >>> turtle.heading()
1597 self._setDegreesPerAU(2*math.pi)
1599 def _go(self, distance):
1600 """move turtle forward by specified distance"""
1601 ende = self._position + self._orient * distance
1604 def _rotate(self, angle):
1605 """Turn turtle counterclockwise by specified angle if angle > 0."""
1606 angle *= self._degreesPerAU
1607 self._orient = self._orient.rotate(angle)
1609 def _goto(self, end):
1610 """move turtle to position end."""
1611 self._position = end
1613 def forward(self, distance):
1614 """Move the turtle forward by the specified distance.
1616 Aliases: forward | fd
1619 distance -- a number (integer or float)
1621 Move the turtle forward by the specified distance, in the direction
1622 the turtle is headed.
1624 Example (for a Turtle instance named turtle):
1625 >>> turtle.position()
1627 >>> turtle.forward(25)
1628 >>> turtle.position()
1630 >>> turtle.forward(-75)
1631 >>> turtle.position()
1636 def back(self, distance):
1637 """Move the turtle backward by distance.
1639 Aliases: back | backward | bk
1642 distance -- a number
1644 Move the turtle backward by distance ,opposite to the direction the
1645 turtle is headed. Do not change the turtle's heading.
1647 Example (for a Turtle instance named turtle):
1648 >>> turtle.position()
1650 >>> turtle.backward(30)
1651 >>> turtle.position()
1656 def right(self, angle):
1657 """Turn turtle right by angle units.
1662 angle -- a number (integer or float)
1664 Turn turtle right by angle units. (Units are by default degrees,
1665 but can be set via the degrees() and radians() functions.)
1666 Angle orientation depends on mode. (See this.)
1668 Example (for a Turtle instance named turtle):
1669 >>> turtle.heading()
1671 >>> turtle.right(45)
1672 >>> turtle.heading()
1675 self._rotate(-angle)
1677 def left(self, angle):
1678 """Turn turtle left by angle units.
1683 angle -- a number (integer or float)
1685 Turn turtle left by angle units. (Units are by default degrees,
1686 but can be set via the degrees() and radians() functions.)
1687 Angle orientation depends on mode. (See this.)
1689 Example (for a Turtle instance named turtle):
1690 >>> turtle.heading()
1693 >>> turtle.heading()
1699 """Return the turtle's current location (x,y), as a Vec2D-vector.
1701 Aliases: pos | position
1705 Example (for a Turtle instance named turtle):
1709 return self._position
1712 """ Return the turtle's x coordinate.
1716 Example (for a Turtle instance named turtle):
1719 >>> turtle.forward(100)
1720 >>> print turtle.xcor()
1723 return self._position[0]
1726 """ Return the turtle's y coordinate
1730 Example (for a Turtle instance named turtle):
1733 >>> turtle.forward(100)
1734 >>> print turtle.ycor()
1737 return self._position[1]
1740 def goto(self, x, y=None):
1741 """Move turtle to an absolute position.
1743 Aliases: setpos | setposition | goto:
1746 x -- a number or a pair/vector of numbers
1749 call: goto(x, y) # two coordinates
1750 --or: goto((x, y)) # a pair (tuple) of coordinates
1751 --or: goto(vec) # e.g. as returned by pos()
1753 Move turtle to an absolute position. If the pen is down,
1754 a line will be drawn. The turtle's orientation does not change.
1756 Example (for a Turtle instance named turtle):
1757 >>> tp = turtle.pos()
1760 >>> turtle.setpos(60,30)
1763 >>> turtle.setpos((20,80))
1766 >>> turtle.setpos(tp)
1771 self._goto(Vec2D(*x))
1773 self._goto(Vec2D(x, y))
1776 """Move turtle to the origin - coordinates (0,0).
1780 Move turtle to the origin - coordinates (0,0) and set its
1781 heading to its start-orientation (which depends on mode).
1783 Example (for a Turtle instance named turtle):
1790 """Set the turtle's first coordinate to x
1793 x -- a number (integer or float)
1795 Set the turtle's first coordinate to x, leave second coordinate
1798 Example (for a Turtle instance named turtle):
1799 >>> turtle.position()
1802 >>> turtle.position()
1805 self._goto(Vec2D(x, self._position[1]))
1808 """Set the turtle's second coordinate to y
1811 y -- a number (integer or float)
1813 Set the turtle's first coordinate to x, second coordinate remains
1816 Example (for a Turtle instance named turtle):
1817 >>> turtle.position()
1819 >>> turtle.sety(-10)
1820 >>> turtle.position()
1823 self._goto(Vec2D(self._position[0], y))
1825 def distance(self, x, y=None):
1826 """Return the distance from the turtle to (x,y) in turtle step units.
1829 x -- a number or a pair/vector of numbers or a turtle instance
1830 y -- a number None None
1832 call: distance(x, y) # two coordinates
1833 --or: distance((x, y)) # a pair (tuple) of coordinates
1834 --or: distance(vec) # e.g. as returned by pos()
1835 --or: distance(mypen) # where mypen is another turtle
1837 Example (for a Turtle instance named turtle):
1840 >>> turtle.distance(30,40)
1844 >>> turtle.distance(pen)
1849 if isinstance(x, Vec2D):
1851 elif isinstance(x, tuple):
1853 elif isinstance(x, TNavigator):
1855 return abs(pos - self._position)
1857 def towards(self, x, y=None):
1858 """Return the angle of the line from the turtle's position to (x, y).
1861 x -- a number or a pair/vector of numbers or a turtle instance
1862 y -- a number None None
1864 call: distance(x, y) # two coordinates
1865 --or: distance((x, y)) # a pair (tuple) of coordinates
1866 --or: distance(vec) # e.g. as returned by pos()
1867 --or: distance(mypen) # where mypen is another turtle
1869 Return the angle, between the line from turtle-position to position
1870 specified by x, y and the turtle's start orientation. (Depends on
1871 modes - "standard
" or "logo
")
1873 Example (for a Turtle instance named turtle):
1876 >>> turtle.towards(0,0)
1881 if isinstance(x, Vec2D):
1883 elif isinstance(x, tuple):
1885 elif isinstance(x, TNavigator):
1887 x, y = pos - self._position
1888 result = round(math.atan2(y, x)*180.0/math.pi, 10) % 360.0
1889 result /= self._degreesPerAU
1890 return (self._angleOffset + self._angleOrient*result) % self._fullcircle
1893 """ Return the turtle's current heading.
1897 Example (for a Turtle instance named turtle):
1899 >>> turtle.heading()
1903 result = round(math.atan2(y, x)*180.0/math.pi, 10) % 360.0
1904 result /= self._degreesPerAU
1905 return (self._angleOffset + self._angleOrient*result) % self._fullcircle
1907 def setheading(self, to_angle):
1908 """Set the orientation of the turtle to to_angle.
1910 Aliases: setheading | seth
1913 to_angle -- a number (integer or float)
1915 Set the orientation of the turtle to to_angle.
1916 Here are some common directions in degrees:
1918 standard - mode: logo-mode:
1919 -------------------|--------------------
1921 90 - north 90 - east
1922 180 - west 180 - south
1923 270 - south 270 - west
1925 Example (for a Turtle instance named turtle):
1926 >>> turtle.setheading(90)
1927 >>> turtle.heading()
1930 angle = (to_angle - self.heading())*self._angleOrient
1931 full = self._fullcircle
1932 angle = (angle+full/2.)%full - full/2.
1935 def circle(self, radius, extent = None, steps = None):
1936 """ Draw a circle with given radius.
1940 extent (optional) -- a number
1941 steps (optional) -- an integer
1943 Draw a circle with given radius. The center is radius units left
1944 of the turtle; extent - an angle - determines which part of the
1945 circle is drawn. If extent is not given, draw the entire circle.
1946 If extent is not a full circle, one endpoint of the arc is the
1947 current pen position. Draw the arc in counterclockwise direction
1948 if radius is positive, otherwise in clockwise direction. Finally
1949 the direction of the turtle is changed by the amount of extent.
1951 As the circle is approximated by an inscribed regular polygon,
1952 steps determines the number of steps to use. If not given,
1953 it will be calculated automatically. Maybe used to draw regular
1956 call: circle(radius) # full circle
1957 --or: circle(radius, extent) # arc
1958 --or: circle(radius, extent, steps)
1959 --or: circle(radius, steps=6) # 6-sided polygon
1961 Example (for a Turtle instance named turtle):
1962 >>> turtle.circle(50)
1963 >>> turtle.circle(120, 180) # semicircle
1966 self.undobuffer.push(["seq
"])
1967 self.undobuffer.cumulate = True
1968 speed = self.speed()
1970 extent = self._fullcircle
1972 frac = abs(extent)/self._fullcircle
1973 steps = 1+int(min(11+abs(radius)/6.0, 59.0)*frac)
1974 w = 1.0 * extent / steps
1976 l = 2.0 * radius * math.sin(w2*math.pi/180.0*self._degreesPerAU)
1978 l, w, w2 = -l, -w, -w2
1986 for i in range(steps):
1993 self._tracer(tr, dl)
1996 self.undobuffer.cumulate = False
1998 ## three dummy methods to be implemented by child class:
2000 def speed(self, s=0):
2001 """dummy method - to be overwritten by child class"""
2002 def _tracer(self, a=None, b=None):
2003 """dummy method - to be overwritten by child class"""
2004 def _delay(self, n=None):
2005 """dummy method - to be overwritten by child class"""
2019 """Drawing part of the RawTurtle.
2020 Implements drawing properties.
2022 def __init__(self, resizemode=_CFG["resizemode
"]):
2023 self._resizemode = resizemode # or "user
" or "noresize
"
2024 self.undobuffer = None
2027 def _reset(self, pencolor=_CFG["pencolor
"],
2028 fillcolor=_CFG["fillcolor
"]):
2031 self._pencolor = pencolor
2032 self._fillcolor = fillcolor
2033 self._drawing = True
2035 self._stretchfactor = (1., 1.)
2036 self._shearfactor = 0.
2038 self._shapetrafo = (1., 0., 0., 1.)
2039 self._outlinewidth = 1
2041 def resizemode(self, rmode=None):
2042 """Set resizemode to one of the values: "auto
", "user
", "noresize
".
2044 (Optional) Argument:
2045 rmode -- one of the strings "auto
", "user
", "noresize
"
2047 Different resizemodes have the following effects:
2048 - "auto
" adapts the appearance of the turtle
2049 corresponding to the value of pensize.
2050 - "user
" adapts the appearance of the turtle according to the
2051 values of stretchfactor and outlinewidth (outline),
2052 which are set by shapesize()
2053 - "noresize
" no adaption of the turtle's appearance takes place.
2054 If no argument is given, return current resizemode.
2055 resizemode("user
") is called by a call of shapesize with arguments.
2058 Examples (for a Turtle instance named turtle):
2059 >>> turtle.resizemode("noresize
")
2060 >>> turtle.resizemode()
2064 return self._resizemode
2065 rmode = rmode.lower()
2066 if rmode in ["auto
", "user
", "noresize
"]:
2067 self.pen(resizemode=rmode)
2069 def pensize(self, width=None):
2070 """Set or return the line thickness.
2072 Aliases: pensize | width
2075 width -- positive number
2077 Set the line thickness to width or return it. If resizemode is set
2078 to "auto
" and turtleshape is a polygon, that polygon is drawn with
2079 the same line thickness. If no argument is given, current pensize
2082 Example (for a Turtle instance named turtle):
2083 >>> turtle.pensize()
2085 turtle.pensize(10) # from here on lines of width 10 are drawn
2088 return self._pensize
2089 self.pen(pensize=width)
2093 """Pull the pen up -- no drawing when moving.
2095 Aliases: penup | pu | up
2099 Example (for a Turtle instance named turtle):
2102 if not self._drawing:
2104 self.pen(pendown=False)
2107 """Pull the pen down -- drawing when moving.
2109 Aliases: pendown | pd | down
2113 Example (for a Turtle instance named turtle):
2114 >>> turtle.pendown()
2118 self.pen(pendown=True)
2121 """Return True if pen is down, False if it's up.
2125 Example (for a Turtle instance named turtle):
2129 >>> turtle.pendown()
2133 return self._drawing
2135 def speed(self, speed=None):
2136 """ Return or set the turtle's speed.
2139 speed -- an integer in the range 0..10 or a speedstring (see below)
2141 Set the turtle's speed to an integer value in the range 0 .. 10.
2142 If no argument is given: return current speed.
2144 If input is a number greater than 10 or smaller than 0.5,
2146 Speedstrings are mapped to speedvalues in the following way:
2152 speeds from 1 to 10 enforce increasingly faster animation of
2153 line drawing and turtle turning.
2156 speed = 0 : *no* animation takes place. forward/back makes turtle jump
2157 and likewise left/right make the turtle turn instantly.
2159 Example (for a Turtle instance named turtle):
2162 speeds = {'fastest':0, 'fast':10, 'normal':6, 'slow':3, 'slowest':1 }
2166 speed = speeds[speed]
2167 elif 0.5 < speed < 10.5:
2168 speed = int(round(speed))
2171 self.pen(speed=speed)
2173 def color(self, *args):
2174 """Return or set the pencolor and fillcolor.
2177 Several input formats are allowed.
2178 They use 0, 1, 2, or 3 arguments as follows:
2181 Return the current pencolor and the current fillcolor
2182 as a pair of color specification strings as are returned
2183 by pencolor and fillcolor.
2184 color(colorstring), color((r,g,b)), color(r,g,b)
2185 inputs as in pencolor, set both, fillcolor and pencolor,
2187 color(colorstring1, colorstring2),
2188 color((r1,g1,b1), (r2,g2,b2))
2189 equivalent to pencolor(colorstring1) and fillcolor(colorstring2)
2190 and analogously, if the other input format is used.
2192 If turtleshape is a polygon, outline and interior of that polygon
2193 is drawn with the newly set colors.
2194 For mor info see: pencolor, fillcolor
2196 Example (for a Turtle instance named turtle):
2197 >>> turtle.color('red', 'green')
2201 >>> color((40, 80, 120), (160, 200, 240))
2203 ('#285078', '#a0c8f0')
2208 pcolor = fcolor = args[0]
2210 pcolor, fcolor = args
2212 pcolor = fcolor = args
2213 pcolor = self._colorstr(pcolor)
2214 fcolor = self._colorstr(fcolor)
2215 self.pen(pencolor=pcolor, fillcolor=fcolor)
2217 return self._color(self._pencolor), self._color(self._fillcolor)
2219 def pencolor(self, *args):
2220 """ Return or set the pencolor.
2223 Four input formats are allowed:
2225 Return the current pencolor as color specification string,
2226 possibly in hex-number format (see example).
2227 May be used as input to another color/pencolor/fillcolor call.
2228 - pencolor(colorstring)
2229 s is a Tk color specification string, such as "red
" or "yellow
"
2230 - pencolor((r, g, b))
2231 *a tuple* of r, g, and b, which represent, an RGB color,
2232 and each of r, g, and b are in the range 0..colormode,
2233 where colormode is either 1.0 or 255
2235 r, g, and b represent an RGB color, and each of r, g, and b
2236 are in the range 0..colormode
2238 If turtleshape is a polygon, the outline of that polygon is drawn
2239 with the newly set pencolor.
2241 Example (for a Turtle instance named turtle):
2242 >>> turtle.pencolor('brown')
2243 >>> tup = (0.2, 0.8, 0.55)
2244 >>> turtle.pencolor(tup)
2245 >>> turtle.pencolor()
2249 color = self._colorstr(args)
2250 if color == self._pencolor:
2252 self.pen(pencolor=color)
2254 return self._color(self._pencolor)
2256 def fillcolor(self, *args):
2257 """ Return or set the fillcolor.
2260 Four input formats are allowed:
2262 Return the current fillcolor as color specification string,
2263 possibly in hex-number format (see example).
2264 May be used as input to another color/pencolor/fillcolor call.
2265 - fillcolor(colorstring)
2266 s is a Tk color specification string, such as "red
" or "yellow
"
2267 - fillcolor((r, g, b))
2268 *a tuple* of r, g, and b, which represent, an RGB color,
2269 and each of r, g, and b are in the range 0..colormode,
2270 where colormode is either 1.0 or 255
2271 - fillcolor(r, g, b)
2272 r, g, and b represent an RGB color, and each of r, g, and b
2273 are in the range 0..colormode
2275 If turtleshape is a polygon, the interior of that polygon is drawn
2276 with the newly set fillcolor.
2278 Example (for a Turtle instance named turtle):
2279 >>> turtle.fillcolor('violet')
2280 >>> col = turtle.pencolor()
2281 >>> turtle.fillcolor(col)
2282 >>> turtle.fillcolor(0, .5, 0)
2285 color = self._colorstr(args)
2286 if color == self._fillcolor:
2288 self.pen(fillcolor=color)
2290 return self._color(self._fillcolor)
2292 def showturtle(self):
2293 """Makes the turtle visible.
2295 Aliases: showturtle | st
2299 Example (for a Turtle instance named turtle):
2300 >>> turtle.hideturtle()
2301 >>> turtle.showturtle()
2303 self.pen(shown=True)
2305 def hideturtle(self):
2306 """Makes the turtle invisible.
2308 Aliases: hideturtle | ht
2312 It's a good idea to do this while you're in the
2313 middle of a complicated drawing, because hiding
2314 the turtle speeds up the drawing observably.
2316 Example (for a Turtle instance named turtle):
2317 >>> turtle.hideturtle()
2319 self.pen(shown=False)
2321 def isvisible(self):
2322 """Return True if the Turtle is shown, False if it's hidden.
2326 Example (for a Turtle instance named turtle):
2327 >>> turtle.hideturtle()
2328 >>> print turtle.isvisible():
2333 def pen(self, pen=None, **pendict):
2334 """Return or set the pen's attributes.
2337 pen -- a dictionary with some or all of the below listed keys.
2338 **pendict -- one or more keyword-arguments with the below
2339 listed keys as keywords.
2341 Return or set the pen's attributes in a 'pen-dictionary'
2342 with the following key/value pairs:
2343 "shown
" : True/False
2344 "pendown
" : True/False
2345 "pencolor
" : color-string or color-tuple
2346 "fillcolor
" : color-string or color-tuple
2347 "pensize
" : positive number
2348 "speed
" : number in range 0..10
2349 "resizemode
" : "auto
" or "user
" or "noresize
"
2350 "stretchfactor
": (positive number, positive number)
2351 "shearfactor
": number
2352 "outline
" : positive number
2355 This dictionary can be used as argument for a subsequent
2356 pen()-call to restore the former pen-state. Moreover one
2357 or more of these attributes can be provided as keyword-arguments.
2358 This can be used to set several pen attributes in one statement.
2361 Examples (for a Turtle instance named turtle):
2362 >>> turtle.pen(fillcolor="black
", pencolor="red
", pensize=10)
2364 {'pensize': 10, 'shown': True, 'resizemode': 'auto', 'outline': 1,
2365 'pencolor': 'red', 'pendown': True, 'fillcolor': 'black',
2366 'stretchfactor': (1,1), 'speed': 3, 'shearfactor': 0.0}
2367 >>> penstate=turtle.pen()
2368 >>> turtle.color("yellow
","")
2371 {'pensize': 10, 'shown': True, 'resizemode': 'auto', 'outline': 1,
2372 'pencolor': 'yellow', 'pendown': False, 'fillcolor': '',
2373 'stretchfactor': (1,1), 'speed': 3, 'shearfactor': 0.0}
2374 >>> p.pen(penstate, fillcolor="green
")
2376 {'pensize': 10, 'shown': True, 'resizemode': 'auto', 'outline': 1,
2377 'pencolor': 'red', 'pendown': True, 'fillcolor': 'green',
2378 'stretchfactor': (1,1), 'speed': 3, 'shearfactor': 0.0}
2380 _pd = {"shown
" : self._shown,
2381 "pendown
" : self._drawing,
2382 "pencolor
" : self._pencolor,
2383 "fillcolor
" : self._fillcolor,
2384 "pensize
" : self._pensize,
2385 "speed
" : self._speed,
2386 "resizemode
" : self._resizemode,
2387 "stretchfactor
" : self._stretchfactor,
2388 "shearfactor
" : self._shearfactor,
2389 "outline
" : self._outlinewidth,
2393 if not (pen or pendict):
2396 if isinstance(pen, dict):
2404 _p_buf[key] = _pd[key]
2407 self.undobuffer.push(("pen
", _p_buf))
2411 if self._drawing != p["pendown
"]:
2414 if isinstance(p["pencolor
"], tuple):
2415 p["pencolor
"] = self._colorstr((p["pencolor
"],))
2416 if self._pencolor != p["pencolor
"]:
2419 if self._pensize != p["pensize
"]:
2424 self._drawing = p["pendown
"]
2426 self._pencolor = p["pencolor
"]
2428 self._pensize = p["pensize
"]
2429 if "fillcolor
" in p:
2430 if isinstance(p["fillcolor
"], tuple):
2431 p["fillcolor
"] = self._colorstr((p["fillcolor
"],))
2432 self._fillcolor = p["fillcolor
"]
2434 self._speed = p["speed
"]
2435 if "resizemode
" in p:
2436 self._resizemode = p["resizemode
"]
2437 if "stretchfactor
" in p:
2438 sf = p["stretchfactor
"]
2439 if isinstance(sf, (int, float)):
2441 self._stretchfactor = sf
2442 if "shearfactor
" in p:
2443 self._shearfactor = p["shearfactor
"]
2445 self._outlinewidth = p["outline
"]
2447 self._shown = p["shown
"]
2449 self._tilt = p["tilt
"]
2450 if "stretchfactor
" in p or "tilt
" in p or "shearfactor
" in p:
2451 scx, scy = self._stretchfactor
2452 shf = self._shearfactor
2453 sa, ca = math.sin(self._tilt), math.cos(self._tilt)
2454 self._shapetrafo = ( scx*ca, scy*(shf*ca + sa),
2455 -scx*sa, scy*(ca - shf*sa))
2458 ## three dummy methods to be implemented by child class:
2460 def _newLine(self, usePos = True):
2461 """dummy method - to be overwritten by child class"""
2462 def _update(self, count=True, forced=False):
2463 """dummy method - to be overwritten by child class"""
2464 def _color(self, args):
2465 """dummy method - to be overwritten by child class"""
2466 def _colorstr(self, args):
2467 """dummy method - to be overwritten by child class"""
2478 class _TurtleImage(object):
2479 """Helper class: Datatype to store Turtle attributes
2482 def __init__(self, screen, shapeIndex):
2483 self.screen = screen
2485 self._setshape(shapeIndex)
2487 def _setshape(self, shapeIndex):
2488 screen = self.screen
2489 self.shapeIndex = shapeIndex
2490 if self._type == "polygon
" == screen._shapes[shapeIndex]._type:
2492 if self._type == "image
" == screen._shapes[shapeIndex]._type:
2494 if self._type in ["image
", "polygon
"]:
2495 screen._delete(self._item)
2496 elif self._type == "compound
":
2497 for item in self._item:
2498 screen._delete(item)
2499 self._type = screen._shapes[shapeIndex]._type
2500 if self._type == "polygon
":
2501 self._item = screen._createpoly()
2502 elif self._type == "image
":
2503 self._item = screen._createimage(screen._shapes["blank
"]._data)
2504 elif self._type == "compound
":
2505 self._item = [screen._createpoly() for item in
2506 screen._shapes[shapeIndex]._data]
2509 class RawTurtle(TPen, TNavigator):
2510 """Animation part of the RawTurtle.
2511 Puts RawTurtle upon a TurtleScreen and provides tools for
2516 def __init__(self, canvas=None,
2517 shape=_CFG["shape
"],
2518 undobuffersize=_CFG["undobuffersize
"],
2519 visible=_CFG["visible
"]):
2520 if isinstance(canvas, _Screen):
2521 self.screen = canvas
2522 elif isinstance(canvas, TurtleScreen):
2523 if canvas not in RawTurtle.screens:
2524 RawTurtle.screens.append(canvas)
2525 self.screen = canvas
2526 elif isinstance(canvas, (ScrolledCanvas, Canvas)):
2527 for screen in RawTurtle.screens:
2528 if screen.cv == canvas:
2529 self.screen = screen
2532 self.screen = TurtleScreen(canvas)
2533 RawTurtle.screens.append(self.screen)
2535 raise TurtleGraphicsError("bad cavas argument
%s" % canvas)
2537 screen = self.screen
2538 TNavigator.__init__(self, screen.mode())
2540 screen._turtles.append(self)
2541 self.drawingLineItem = screen._createline()
2542 self.turtle = _TurtleImage(screen, shape)
2544 self._creatingPoly = False
2545 self._fillitem = self._fillpath = None
2546 self._shown = visible
2547 self._hidden_from_screen = False
2548 self.currentLineItem = screen._createline()
2549 self.currentLine = [self._position]
2550 self.items = [self.currentLineItem]
2551 self.stampItems = []
2552 self._undobuffersize = undobuffersize
2553 self.undobuffer = Tbuffer(undobuffersize)
2557 """Delete the turtle's drawings and restore its default values.
2561 Delete the turtle's drawings from the screen, re-center the turtle
2562 and set variables to the default values.
2564 Example (for a Turtle instance named turtle):
2565 >>> turtle.position()
2567 >>> turtle.heading()
2570 >>> turtle.position()
2572 >>> turtle.heading()
2575 TNavigator.reset(self)
2581 def setundobuffer(self, size):
2582 """Set or disable undobuffer.
2585 size -- an integer or None
2587 If size is an integer an empty undobuffer of given size is installed.
2588 Size gives the maximum number of turtle-actions that can be undone
2589 by the undo() function.
2590 If size is None, no undobuffer is present.
2592 Example (for a Turtle instance named turtle):
2593 >>> turtle.setundobuffer(42)
2596 self.undobuffer = None
2598 self.undobuffer = Tbuffer(size)
2600 def undobufferentries(self):
2601 """Return count of entries in the undobuffer.
2605 Example (for a Turtle instance named turtle):
2606 >>> while undobufferentries():
2609 if self.undobuffer is None:
2611 return self.undobuffer.nr_of_items()
2614 """Delete all of pen's drawings"""
2615 self._fillitem = self._fillpath = None
2616 for item in self.items:
2617 self.screen._delete(item)
2618 self.currentLineItem = self.screen._createline()
2619 self.currentLine = []
2621 self.currentLine.append(self._position)
2622 self.items = [self.currentLineItem]
2624 self.setundobuffer(self._undobuffersize)
2628 """Delete the turtle's drawings from the screen. Do not move turtle.
2632 Delete the turtle's drawings from the screen. Do not move turtle.
2633 State and position of the turtle as well as drawings of other
2634 turtles are not affected.
2636 Examples (for a Turtle instance named turtle):
2642 def _update_data(self):
2643 self.screen._incrementudc()
2644 if self.screen._updatecounter != 0:
2646 if len(self.currentLine)>1:
2647 self.screen._drawline(self.currentLineItem, self.currentLine,
2648 self._pencolor, self._pensize)
2651 """Perform a Turtle-data update.
2653 screen = self.screen
2654 if screen._tracing == 0:
2656 elif screen._tracing == 1:
2659 screen._update() # TurtleScreenBase
2660 screen._delay(screen._delayvalue) # TurtleScreenBase
2663 if screen._updatecounter == 0:
2664 for t in screen.turtles():
2668 def _tracer(self, flag=None, delay=None):
2669 """Turns turtle animation on/off and set delay for update drawings.
2672 n -- nonnegative integer
2673 delay -- nonnegative integer
2675 If n is given, only each n-th regular screen update is really performed.
2676 (Can be used to accelerate the drawing of complex graphics.)
2677 Second arguments sets delay value (see RawTurtle.delay())
2679 Example (for a Turtle instance named turtle):
2680 >>> turtle.tracer(8, 25)
2682 >>> for i in range(200):
2687 return self.screen.tracer(flag, delay)
2689 def _color(self, args):
2690 return self.screen._color(args)
2692 def _colorstr(self, args):
2693 return self.screen._colorstr(args)
2695 def _cc(self, args):
2696 """Convert colortriples to hexstrings.
2698 if isinstance(args, str):
2703 raise TurtleGraphicsError("bad color arguments
: %s" % str(args))
2704 if self.screen._colormode == 1.0:
2705 r, g, b = [round(255.0*x) for x in (r, g, b)]
2706 if not ((0 <= r <= 255) and (0 <= g <= 255) and (0 <= b <= 255)):
2707 raise TurtleGraphicsError("bad color sequence
: %s" % str(args))
2708 return "#%02x%02x%02x" % (r, g, b)
2711 """Create and return a clone of the turtle.
2715 Create and return a clone of the turtle with same position, heading
2716 and turtle properties.
2718 Example (for a Turtle instance named mick):
2722 screen
= self
.screen
2723 self
._newLine
(self
._drawing
)
2725 turtle
= self
.turtle
2727 self
.turtle
= None # too make self deepcopy-able
2731 self
.screen
= screen
2732 self
.turtle
= turtle
2735 q
.turtle
= _TurtleImage(screen
, self
.turtle
.shapeIndex
)
2737 screen
._turtles
.append(q
)
2738 ttype
= screen
._shapes
[self
.turtle
.shapeIndex
]._type
2739 if ttype
== "polygon":
2740 q
.turtle
._item
= screen
._createpoly
()
2741 elif ttype
== "image":
2742 q
.turtle
._item
= screen
._createimage
(screen
._shapes
["blank"]._data
)
2743 elif ttype
== "compound":
2744 q
.turtle
._item
= [screen
._createpoly
() for item
in
2745 screen
._shapes
[self
.turtle
.shapeIndex
]._data
]
2746 q
.currentLineItem
= screen
._createline
()
2750 def shape(self
, name
=None):
2751 """Set turtle shape to shape with given name / return current shapename.
2754 name -- a string, which is a valid shapename
2756 Set turtle shape to shape with given name or, if name is not given,
2757 return name of current shape.
2758 Shape with name must exist in the TurtleScreen's shape dictionary.
2759 Initially there are the following polygon shapes:
2760 'arrow', 'turtle', 'circle', 'square', 'triangle', 'classic'.
2761 To learn about how to deal with shapes see Screen-method register_shape.
2763 Example (for a Turtle instance named turtle):
2766 >>> turtle.shape("turtle")
2771 return self
.turtle
.shapeIndex
2772 if not name
in self
.screen
.getshapes():
2773 raise TurtleGraphicsError("There is no shape named %s" % name
)
2774 self
.turtle
._setshape
(name
)
2777 def shapesize(self
, stretch_wid
=None, stretch_len
=None, outline
=None):
2778 """Set/return turtle's stretchfactors/outline. Set resizemode to "user".
2780 Optinonal arguments:
2781 stretch_wid : positive number
2782 stretch_len : positive number
2783 outline : positive number
2785 Return or set the pen's attributes x/y-stretchfactors and/or outline.
2786 Set resizemode to "user".
2787 If and only if resizemode is set to "user", the turtle will be displayed
2788 stretched according to its stretchfactors:
2789 stretch_wid is stretchfactor perpendicular to orientation
2790 stretch_len is stretchfactor in direction of turtles orientation.
2791 outline determines the width of the shapes's outline.
2793 Examples (for a Turtle instance named turtle):
2794 >>> turtle.resizemode("user")
2795 >>> turtle.shapesize(5, 5, 12)
2796 >>> turtle.shapesize(outline=8)
2798 if stretch_wid
is stretch_len
is outline
is None:
2799 stretch_wid
, stretch_len
= self
._stretchfactor
2800 return stretch_wid
, stretch_len
, self
._outlinewidth
2801 if stretch_wid
== 0 or stretch_len
== 0:
2802 raise TurtleGraphicsError("stretch_wid/stretch_len must not be zero")
2803 if stretch_wid
is not None:
2804 if stretch_len
is None:
2805 stretchfactor
= stretch_wid
, stretch_wid
2807 stretchfactor
= stretch_wid
, stretch_len
2808 elif stretch_len
is not None:
2809 stretchfactor
= self
._stretchfactor
[0], stretch_len
2811 stretchfactor
= self
._stretchfactor
2813 outline
= self
._outlinewidth
2814 self
.pen(resizemode
="user",
2815 stretchfactor
=stretchfactor
, outline
=outline
)
2817 def shearfactor(self
, shear
=None):
2818 """Set or return the current shearfactor.
2820 Optional argument: shear -- number, tangent of the shear angle
2822 Shear the turtleshape according to the given shearfactor shear,
2823 which is the tangent of the shear angle. DO NOT change the
2824 turtle's heading (direction of movement).
2825 If shear is not given: return the current shearfactor, i. e. the
2826 tangent of the shear angle, by which lines parallel to the
2827 heading of the turtle are sheared.
2829 Examples (for a Turtle instance named turtle):
2830 >>> turtle.shape("circle")
2831 >>> turtle.shapesize(5,2)
2832 >>> turtle.shearfactor(0.5)
2833 >>> turtle.shearfactor()
2837 return self
._shearfactor
2838 self
.pen(resizemode
="user", shearfactor
=shear
)
2840 def settiltangle(self
, angle
):
2841 """Rotate the turtleshape to point in the specified direction
2843 Argument: angle -- number
2845 Rotate the turtleshape to point in the direction specified by angle,
2846 regardless of its current tilt-angle. DO NOT change the turtle's
2847 heading (direction of movement).
2850 Examples (for a Turtle instance named turtle):
2851 >>> turtle.shape("circle")
2852 >>> turtle.shapesize(5,2)
2853 >>> turtle.settiltangle(45)
2856 >>> turtle.settiltangle(-45)
2860 tilt
= -angle
* self
._degreesPerAU
* self
._angleOrient
2861 tilt
= (tilt
* math
.pi
/ 180.0) % (2*math
.pi
)
2862 self
.pen(resizemode
="user", tilt
=tilt
)
2864 def tiltangle(self
, angle
=None):
2865 """Set or return the current tilt-angle.
2867 Optional argument: angle -- number
2869 Rotate the turtleshape to point in the direction specified by angle,
2870 regardless of its current tilt-angle. DO NOT change the turtle's
2871 heading (direction of movement).
2872 If angle is not given: return the current tilt-angle, i. e. the angle
2873 between the orientation of the turtleshape and the heading of the
2874 turtle (its direction of movement).
2876 Deprecated since Python 3.1
2878 Examples (for a Turtle instance named turtle):
2879 >>> turtle.shape("circle")
2880 >>> turtle.shapesize(5,2)
2882 >>> turtle.tiltangle()
2886 tilt
= -self
._tilt
* (180.0/math
.pi
) * self
._angleOrient
2887 return (tilt
/ self
._degreesPerAU
) % self
._fullcircle
2889 self
.settiltangle(angle
)
2891 def tilt(self
, angle
):
2892 """Rotate the turtleshape by angle.
2897 Rotate the turtleshape by angle from its current tilt-angle,
2898 but do NOT change the turtle's heading (direction of movement).
2900 Examples (for a Turtle instance named turtle):
2901 >>> turtle.shape("circle")
2902 >>> turtle.shapesize(5,2)
2908 self
.settiltangle(angle
+ self
.tiltangle())
2910 def shapetransform(self
, t11
=None, t12
=None, t21
=None, t22
=None):
2911 """Set or return the current transformation matrix of the turtle shape.
2913 Optional arguments: t11, t12, t21, t22 -- numbers.
2915 If none of the matrix elements are given, return the transformation
2917 Otherwise set the given elements and transform the turtleshape
2918 according to the matrix consisting of first row t11, t12 and
2920 Modify stretchfactor, shearfactor and tiltangle according to the
2923 Examples (for a Turtle instance named turtle):
2924 >>> turtle.shape("square")
2925 >>> turtle.shapesize(4,2)
2926 >>> turtle.shearfactor(-0.5)
2927 >>> turtle.shapetransform()
2928 >>> (4.0, -1.0, -0.0, 2.0)
2930 if t11
is t12
is t21
is t22
is None:
2931 return self
._shapetrafo
2932 m11
, m12
, m21
, m22
= self
._shapetrafo
2933 if t11
is not None: m11
= t11
2934 if t12
is not None: m12
= t12
2935 if t21
is not None: m21
= t21
2936 if t22
is not None: m22
= t22
2937 if t11
* t22
- t12
* t21
== 0:
2938 raise TurtleGraphicsError("Bad shape transform matrix: must not be singular")
2939 self
._shapetrafo
= (m11
, m12
, m21
, m22
)
2940 alfa
= math
.atan2(-m21
, m11
) % (2 * math
.pi
)
2941 sa
, ca
= math
.sin(alfa
), math
.cos(alfa
)
2942 a11
, a12
, a21
, a22
= (ca
*m11
- sa
*m21
, ca
*m12
- sa
*m22
,
2943 sa
*m11
+ ca
*m21
, sa
*m12
+ ca
*m22
)
2944 self
._stretchfactor
= a11
, a22
2945 self
._shearfactor
= a12
/a22
2950 def _polytrafo(self
, poly
):
2951 """Computes transformed polygon shapes from a shape
2952 according to current position and heading.
2954 screen
= self
.screen
2955 p0
, p1
= self
._position
2956 e0
, e1
= self
._orient
2957 e
= Vec2D(e0
, e1
* screen
.yscale
/ screen
.xscale
)
2958 e0
, e1
= (1.0 / abs(e
)) * e
2959 return [(p0
+(e1
*x
+e0
*y
)/screen
.xscale
, p1
+(-e0
*x
+e1
*y
)/screen
.yscale
)
2962 def get_shapepoly(self
):
2963 """Return the current shape polygon as tuple of coordinate pairs.
2967 Examples (for a Turtle instance named turtle):
2968 >>> turtle.shape("square")
2969 >>> turtle.shapetransform(4, -1, 0, 2)
2970 >>> turtle.get_shapepoly()
2971 ((50, -20), (30, 20), (-50, 20), (-30, -20))
2974 shape
= self
.screen
._shapes
[self
.turtle
.shapeIndex
]
2975 if shape
._type
== "polygon":
2976 return self
._getshapepoly
(shape
._data
, shape
._type
== "compound")
2979 def _getshapepoly(self
, polygon
, compound
=False):
2980 """Calculate transformed shape polygon according to resizemode
2983 if self
._resizemode
== "user" or compound
:
2984 t11
, t12
, t21
, t22
= self
._shapetrafo
2985 elif self
._resizemode
== "auto":
2986 l
= max(1, self
._pensize
/5.0)
2987 t11
, t12
, t21
, t22
= l
, 0, 0, l
2988 elif self
._resizemode
== "noresize":
2990 return tuple([(t11
*x
+ t12
*y
, t21
*x
+ t22
*y
) for (x
, y
) in polygon
])
2992 def _drawturtle(self
):
2993 """Manages the correct rendering of the turtle with respect to
2994 its shape, resizemode, stretch and tilt etc."""
2995 screen
= self
.screen
2996 shape
= screen
._shapes
[self
.turtle
.shapeIndex
]
2998 titem
= self
.turtle
._item
2999 if self
._shown
and screen
._updatecounter
== 0 and screen
._tracing
> 0:
3000 self
._hidden
_from
_screen
= False
3001 tshape
= shape
._data
3002 if ttype
== "polygon":
3003 if self
._resizemode
== "noresize": w
= 1
3004 elif self
._resizemode
== "auto": w
= self
._pensize
3005 else: w
=self
._outlinewidth
3006 shape
= self
._polytrafo
(self
._getshapepoly
(tshape
))
3007 fc
, oc
= self
._fillcolor
, self
._pencolor
3008 screen
._drawpoly
(titem
, shape
, fill
=fc
, outline
=oc
,
3010 elif ttype
== "image":
3011 screen
._drawimage
(titem
, self
._position
, tshape
)
3012 elif ttype
== "compound":
3013 for item
, (poly
, fc
, oc
) in zip(titem
, tshape
):
3014 poly
= self
._polytrafo
(self
._getshapepoly
(poly
, True))
3015 screen
._drawpoly
(item
, poly
, fill
=self
._cc
(fc
),
3016 outline
=self
._cc
(oc
), width
=self
._outlinewidth
, top
=True)
3018 if self
._hidden
_from
_screen
:
3020 if ttype
== "polygon":
3021 screen
._drawpoly
(titem
, ((0, 0), (0, 0), (0, 0)), "", "")
3022 elif ttype
== "image":
3023 screen
._drawimage
(titem
, self
._position
,
3024 screen
._shapes
["blank"]._data
)
3025 elif ttype
== "compound":
3027 screen
._drawpoly
(item
, ((0, 0), (0, 0), (0, 0)), "", "")
3028 self
._hidden
_from
_screen
= True
3030 ############################## stamp stuff ###############################
3033 """Stamp a copy of the turtleshape onto the canvas and return its id.
3037 Stamp a copy of the turtle shape onto the canvas at the current
3038 turtle position. Return a stamp_id for that stamp, which can be
3039 used to delete it by calling clearstamp(stamp_id).
3041 Example (for a Turtle instance named turtle):
3042 >>> turtle.color("blue")
3047 screen
= self
.screen
3048 shape
= screen
._shapes
[self
.turtle
.shapeIndex
]
3050 tshape
= shape
._data
3051 if ttype
== "polygon":
3052 stitem
= screen
._createpoly
()
3053 if self
._resizemode
== "noresize": w
= 1
3054 elif self
._resizemode
== "auto": w
= self
._pensize
3055 else: w
=self
._outlinewidth
3056 shape
= self
._polytrafo
(self
._getshapepoly
(tshape
))
3057 fc
, oc
= self
._fillcolor
, self
._pencolor
3058 screen
._drawpoly
(stitem
, shape
, fill
=fc
, outline
=oc
,
3060 elif ttype
== "image":
3061 stitem
= screen
._createimage
("")
3062 screen
._drawimage
(stitem
, self
._position
, tshape
)
3063 elif ttype
== "compound":
3065 for element
in tshape
:
3066 item
= screen
._createpoly
()
3068 stitem
= tuple(stitem
)
3069 for item
, (poly
, fc
, oc
) in zip(stitem
, tshape
):
3070 poly
= self
._polytrafo
(self
._getshapepoly
(poly
, True))
3071 screen
._drawpoly
(item
, poly
, fill
=self
._cc
(fc
),
3072 outline
=self
._cc
(oc
), width
=self
._outlinewidth
, top
=True)
3073 self
.stampItems
.append(stitem
)
3074 self
.undobuffer
.push(("stamp", stitem
))
3077 def _clearstamp(self
, stampid
):
3078 """does the work for clearstamp() and clearstamps()
3080 if stampid
in self
.stampItems
:
3081 if isinstance(stampid
, tuple):
3082 for subitem
in stampid
:
3083 self
.screen
._delete
(subitem
)
3085 self
.screen
._delete
(stampid
)
3086 self
.stampItems
.remove(stampid
)
3087 # Delete stampitem from undobuffer if necessary
3088 # if clearstamp is called directly.
3089 item
= ("stamp", stampid
)
3090 buf
= self
.undobuffer
3091 if item
not in buf
.buffer:
3093 index
= buf
.buffer.index(item
)
3094 buf
.buffer.remove(item
)
3095 if index
<= buf
.ptr
:
3096 buf
.ptr
= (buf
.ptr
- 1) % buf
.bufsize
3097 buf
.buffer.insert((buf
.ptr
+1)%buf
.bufsize
, [None])
3099 def clearstamp(self
, stampid
):
3100 """Delete stamp with given stampid
3103 stampid - an integer, must be return value of previous stamp() call.
3105 Example (for a Turtle instance named turtle):
3106 >>> turtle.color("blue")
3107 >>> astamp = turtle.stamp()
3109 >>> turtle.clearstamp(astamp)
3111 self
._clearstamp
(stampid
)
3114 def clearstamps(self
, n
=None):
3115 """Delete all or first/last n of turtle's stamps.
3120 If n is None, delete all of pen's stamps,
3121 else if n > 0 delete first n stamps
3122 else if n < 0 delete last n stamps.
3124 Example (for a Turtle instance named turtle):
3125 >>> for i in range(8):
3126 turtle.stamp(); turtle.fd(30)
3128 >>> turtle.clearstamps(2)
3129 >>> turtle.clearstamps(-2)
3130 >>> turtle.clearstamps()
3133 toDelete
= self
.stampItems
[:]
3135 toDelete
= self
.stampItems
[:n
]
3137 toDelete
= self
.stampItems
[n
:]
3138 for item
in toDelete
:
3139 self
._clearstamp
(item
)
3142 def _goto(self
, end
):
3143 """Move the pen to the point end, thereby drawing a line
3144 if pen is down. All other methodes for turtle movement depend
3147 ## Version mit undo-stuff
3148 go_modes
= ( self
._drawing
,
3151 isinstance(self
._fillpath
, list))
3152 screen
= self
.screen
3153 undo_entry
= ("go", self
._position
, end
, go_modes
,
3154 (self
.currentLineItem
,
3155 self
.currentLine
[:],
3156 screen
._pointlist
(self
.currentLineItem
),
3160 self
.undobuffer
.push(undo_entry
)
3161 start
= self
._position
3162 if self
._speed
and screen
._tracing
== 1:
3164 diffsq
= (diff
[0]*screen
.xscale
)**2 + (diff
[1]*screen
.yscale
)**2
3165 nhops
= 1+int((diffsq
**0.5)/(3*(1.1**self
._speed
)*self
._speed
))
3166 delta
= diff
* (1.0/nhops
)
3167 for n
in range(1, nhops
):
3172 self
._position
= start
+ delta
* n
3174 screen
._drawline
(self
.drawingLineItem
,
3175 (start
, self
._position
),
3176 self
._pencolor
, self
._pensize
, top
)
3179 screen
._drawline
(self
.drawingLineItem
, ((0, 0), (0, 0)),
3180 fill
="", width
=self
._pensize
)
3181 # Turtle now at end,
3182 if self
._drawing
: # now update currentLine
3183 self
.currentLine
.append(end
)
3184 if isinstance(self
._fillpath
, list):
3185 self
._fillpath
.append(end
)
3186 ###### vererbung!!!!!!!!!!!!!!!!!!!!!!
3187 self
._position
= end
3188 if self
._creatingPoly
:
3189 self
._poly
.append(end
)
3190 if len(self
.currentLine
) > 42: # 42! answer to the ultimate question
3191 # of life, the universe and everything
3193 self
._update
() #count=True)
3195 def _undogoto(self
, entry
):
3196 """Reverse a _goto. Used for undo()
3198 old
, new
, go_modes
, coodata
= entry
3199 drawing
, pc
, ps
, filling
= go_modes
3200 cLI
, cL
, pl
, items
= coodata
3201 screen
= self
.screen
3202 if abs(self
._position
- new
) > 0.5:
3203 print ("undogoto: HALLO-DA-STIMMT-WAS-NICHT!")
3204 # restore former situation
3205 self
.currentLineItem
= cLI
3206 self
.currentLine
= cL
3208 if pl
== [(0, 0), (0, 0)]:
3212 screen
._drawline
(cLI
, pl
, fill
=usepc
, width
=ps
)
3214 todelete
= [i
for i
in self
.items
if (i
not in items
) and
3215 (screen
._type
(i
) == "line")]
3218 self
.items
.remove(i
)
3221 if self
._speed
and screen
._tracing
== 1:
3223 diffsq
= (diff
[0]*screen
.xscale
)**2 + (diff
[1]*screen
.yscale
)**2
3224 nhops
= 1+int((diffsq
**0.5)/(3*(1.1**self
._speed
)*self
._speed
))
3225 delta
= diff
* (1.0/nhops
)
3226 for n
in range(1, nhops
):
3231 self
._position
= new
+ delta
* n
3233 screen
._drawline
(self
.drawingLineItem
,
3234 (start
, self
._position
),
3238 screen
._drawline
(self
.drawingLineItem
, ((0, 0), (0, 0)),
3240 # Turtle now at position old,
3241 self
._position
= old
3242 ## if undo is done during crating a polygon, the last vertex
3243 ## will be deleted. if the polygon is entirel deleted,
3244 ## creatigPoly will be set to False.
3245 ## Polygons created before the last one will not be affected by undo()
3246 if self
._creatingPoly
:
3247 if len(self
._poly
) > 0:
3249 if self
._poly
== []:
3250 self
._creatingPoly
= False
3253 if self
._fillpath
== []:
3254 self
._fillpath
= None
3255 print("Unwahrscheinlich in _undogoto!")
3256 elif self
._fillpath
is not None:
3257 self
._fillpath
.pop()
3258 self
._update
() #count=True)
3260 def _rotate(self
, angle
):
3261 """Turns pen clockwise by angle.
3264 self
.undobuffer
.push(("rot", angle
, self
._degreesPerAU
))
3265 angle
*= self
._degreesPerAU
3266 neworient
= self
._orient
.rotate(angle
)
3267 tracing
= self
.screen
._tracing
3268 if tracing
== 1 and self
._speed
> 0:
3269 anglevel
= 3.0 * self
._speed
3270 steps
= 1 + int(abs(angle
)/anglevel
)
3271 delta
= 1.0*angle
/steps
3272 for _
in range(steps
):
3273 self
._orient
= self
._orient
.rotate(delta
)
3275 self
._orient
= neworient
3278 def _newLine(self
, usePos
=True):
3279 """Closes current line item and starts a new one.
3280 Remark: if current line became too long, animation
3281 performance (via _drawline) slowed down considerably.
3283 if len(self
.currentLine
) > 1:
3284 self
.screen
._drawline
(self
.currentLineItem
, self
.currentLine
,
3285 self
._pencolor
, self
._pensize
)
3286 self
.currentLineItem
= self
.screen
._createline
()
3287 self
.items
.append(self
.currentLineItem
)
3289 self
.screen
._drawline
(self
.currentLineItem
, top
=True)
3290 self
.currentLine
= []
3292 self
.currentLine
= [self
._position
]
3295 """Return fillstate (True if filling, False else).
3299 Example (for a Turtle instance named turtle):
3300 >>> turtle.begin_fill()
3301 >>> if turtle.filling():
3306 return isinstance(self
._fillpath
, list)
3308 def begin_fill(self
):
3309 """Called just before drawing a shape to be filled.
3313 Example (for a Turtle instance named turtle):
3314 >>> turtle.color("black", "red")
3315 >>> turtle.begin_fill()
3316 >>> turtle.circle(60)
3317 >>> turtle.end_fill()
3319 if not self
.filling():
3320 self
._fillitem
= self
.screen
._createpoly
()
3321 self
.items
.append(self
._fillitem
)
3322 self
._fillpath
= [self
._position
]
3325 self
.undobuffer
.push(("beginfill", self
._fillitem
))
3330 """Fill the shape drawn after the call begin_fill().
3334 Example (for a Turtle instance named turtle):
3335 >>> turtle.color("black", "red")
3336 >>> turtle.begin_fill()
3337 >>> turtle.circle(60)
3338 >>> turtle.end_fill()
3341 if len(self
._fillpath
) > 2:
3342 self
.screen
._drawpoly
(self
._fillitem
, self
._fillpath
,
3343 fill
=self
._fillcolor
)
3345 self
.undobuffer
.push(("dofill", self
._fillitem
))
3346 self
._fillitem
= self
._fillpath
= None
3349 def dot(self
, size
=None, *color
):
3350 """Draw a dot with diameter size, using color.
3353 size -- an integer >= 1 (if given)
3354 color -- a colorstring or a numeric color tuple
3356 Draw a circular dot with diameter size, using color.
3357 If size is not given, the maximum of pensize+4 and 2*pensize is used.
3359 Example (for a Turtle instance named turtle):
3361 >>> turtle.fd(50); turtle.dot(20, "blue"); turtle.fd(50)
3364 if isinstance(size
, (str, tuple)):
3365 color
= self
._colorstr
(size
)
3366 size
= self
._pensize
+ max(self
._pensize
, 4)
3368 color
= self
._pencolor
3370 size
= self
._pensize
+ max(self
._pensize
, 4)
3373 size
= self
._pensize
+ max(self
._pensize
, 4)
3374 color
= self
._colorstr
(color
)
3375 if hasattr(self
.screen
, "_dot"):
3376 item
= self
.screen
._dot
(self
._position
, size
, color
)
3377 self
.items
.append(item
)
3379 self
.undobuffer
.push(("dot", item
))
3383 self
.undobuffer
.push(["seq"])
3384 self
.undobuffer
.cumulate
= True
3386 if self
.resizemode() == 'auto':
3390 self
.pencolor(color
)
3395 self
.undobuffer
.cumulate
= False
3397 def _write(self
, txt
, align
, font
):
3398 """Performs the writing for write()
3400 item
, end
= self
.screen
._write
(self
._position
, txt
, align
, font
,
3402 self
.items
.append(item
)
3404 self
.undobuffer
.push(("wri", item
))
3407 def write(self
, arg
, move
=False, align
="left", font
=("Arial", 8, "normal")):
3408 """Write text at the current turtle position.
3411 arg -- info, which is to be written to the TurtleScreen
3412 move (optional) -- True/False
3413 align (optional) -- one of the strings "left", "center" or right"
3414 font (optional) -- a triple (fontname, fontsize, fonttype)
3416 Write text - the string representation of arg - at the current
3417 turtle position according to align ("left", "center" or right")
3418 and with the given font.
3419 If move is True, the pen is moved to the bottom-right corner
3420 of the text. By default, move is False.
3422 Example (for a Turtle instance named turtle):
3423 >>> turtle.write('Home = ', True, align="center")
3424 >>> turtle.write((0,0), True)
3427 self
.undobuffer
.push(["seq"])
3428 self
.undobuffer
.cumulate
= True
3429 end
= self
._write
(str(arg
), align
.lower(), font
)
3434 self
.undobuffer
.cumulate
= False
3436 def begin_poly(self
):
3437 """Start recording the vertices of a polygon.
3441 Start recording the vertices of a polygon. Current turtle position
3442 is first point of polygon.
3444 Example (for a Turtle instance named turtle):
3445 >>> turtle.begin_poly()
3447 self
._poly
= [self
._position
]
3448 self
._creatingPoly
= True
3451 """Stop recording the vertices of a polygon.
3455 Stop recording the vertices of a polygon. Current turtle position is
3456 last point of polygon. This will be connected with the first point.
3458 Example (for a Turtle instance named turtle):
3459 >>> turtle.end_poly()
3461 self
._creatingPoly
= False
3464 """Return the lastly recorded polygon.
3468 Example (for a Turtle instance named turtle):
3469 >>> p = turtle.get_poly()
3470 >>> turtle.register_shape("myFavouriteShape", p)
3472 ## check if there is any poly?
3473 if self
._poly
is not None:
3474 return tuple(self
._poly
)
3476 def getscreen(self
):
3477 """Return the TurtleScreen object, the turtle is drawing on.
3481 Return the TurtleScreen object, the turtle is drawing on.
3482 So TurtleScreen-methods can be called for that object.
3484 Example (for a Turtle instance named turtle):
3485 >>> ts = turtle.getscreen()
3487 <turtle.TurtleScreen object at 0x0106B770>
3488 >>> ts.bgcolor("pink")
3492 def getturtle(self
):
3493 """Return the Turtleobject itself.
3497 Only reasonable use: as a function to return the 'anonymous turtle':
3500 >>> pet = getturtle()
3503 <turtle.Turtle object at 0x0187D810>
3505 [<turtle.Turtle object at 0x0187D810>]
3512 ################################################################
3513 ### screen oriented methods recurring to methods of TurtleScreen
3514 ################################################################
3516 def _delay(self
, delay
=None):
3517 """Set delay value which determines speed of turtle animation.
3519 return self
.screen
.delay(delay
)
3521 def onclick(self
, fun
, btn
=1, add
=None):
3522 """Bind fun to mouse-click event on this turtle on canvas.
3525 fun -- a function with two arguments, to which will be assigned
3526 the coordinates of the clicked point on the canvas.
3527 num -- number of the mouse-button defaults to 1 (left mouse button).
3528 add -- True or False. If True, new binding will be added, otherwise
3529 it will replace a former binding.
3531 Example for the anonymous turtle, i. e. the procedural way:
3536 >>> onclick(turn) # Now clicking into the turtle will turn it.
3537 >>> onclick(None) # event-binding will be removed
3539 self
.screen
._onclick
(self
.turtle
._item
, fun
, btn
, add
)
3542 def onrelease(self
, fun
, btn
=1, add
=None):
3543 """Bind fun to mouse-button-release event on this turtle on canvas.
3546 fun -- a function with two arguments, to which will be assigned
3547 the coordinates of the clicked point on the canvas.
3548 num -- number of the mouse-button defaults to 1 (left mouse button).
3550 Example (for a MyTurtle instance named joe):
3551 >>> class MyTurtle(Turtle):
3553 self.fillcolor("red")
3554 def unglow(self,x,y):
3557 >>> joe = MyTurtle()
3558 >>> joe.onclick(joe.glow)
3559 >>> joe.onrelease(joe.unglow)
3560 ### clicking on joe turns fillcolor red,
3561 ### unclicking turns it to transparent.
3563 self
.screen
._onrelease
(self
.turtle
._item
, fun
, btn
, add
)
3566 def ondrag(self
, fun
, btn
=1, add
=None):
3567 """Bind fun to mouse-move event on this turtle on canvas.
3570 fun -- a function with two arguments, to which will be assigned
3571 the coordinates of the clicked point on the canvas.
3572 num -- number of the mouse-button defaults to 1 (left mouse button).
3574 Every sequence of mouse-move-events on a turtle is preceded by a
3575 mouse-click event on that turtle.
3577 Example (for a Turtle instance named turtle):
3578 >>> turtle.ondrag(turtle.goto)
3580 ### Subsequently clicking and dragging a Turtle will
3581 ### move it across the screen thereby producing handdrawings
3582 ### (if pen is down).
3584 self
.screen
._ondrag
(self
.turtle
._item
, fun
, btn
, add
)
3587 def _undo(self
, action
, data
):
3588 """Does the main part of the work for undo()
3590 if self
.undobuffer
is None:
3593 angle
, degPAU
= data
3594 self
._rotate
(-angle
*degPAU
/self
._degreesPerAU
)
3595 dummy
= self
.undobuffer
.pop()
3596 elif action
== "stamp":
3598 self
.clearstamp(stitem
)
3599 elif action
== "go":
3600 self
._undogoto
(data
)
3601 elif action
in ["wri", "dot"]:
3603 self
.screen
._delete
(item
)
3604 self
.items
.remove(item
)
3605 elif action
== "dofill":
3607 self
.screen
._drawpoly
(item
, ((0, 0),(0, 0),(0, 0)),
3608 fill
="", outline
="")
3609 elif action
== "beginfill":
3611 self
._fillitem
= self
._fillpath
= None
3612 if item
in self
.items
:
3613 self
.screen
._delete
(item
)
3614 self
.items
.remove(item
)
3615 elif action
== "pen":
3616 TPen
.pen(self
, data
[0])
3617 self
.undobuffer
.pop()
3620 """undo (repeatedly) the last turtle action.
3624 undo (repeatedly) the last turtle action.
3625 Number of available undo actions is determined by the size of
3628 Example (for a Turtle instance named turtle):
3629 >>> for i in range(4):
3630 turtle.fd(50); turtle.lt(80)
3632 >>> for i in range(8):
3635 if self
.undobuffer
is None:
3637 item
= self
.undobuffer
.pop()
3643 self
._undo
(item
[0], item
[1:])
3645 self
._undo
(action
, data
)
3647 turtlesize
= shapesize
3651 ### Screen - Singleton ########################
3654 """Return the singleton screen object.
3655 If none exists at the moment, create a new one and return it,
3656 else return the existing one."""
3657 if Turtle
._screen
is None:
3658 Turtle
._screen
= _Screen()
3659 return Turtle
._screen
3661 class _Screen(TurtleScreen
):
3665 _title
= _CFG
["title"]
3668 # XXX there is no need for this code to be conditional,
3669 # as there will be only a single _Screen instance, anyway
3670 # XXX actually, the turtle demo is injecting root window,
3671 # so perhaps the conditional creation of a root should be
3672 # preserved (perhaps by passing it as an optional parameter)
3673 if _Screen
._root
is None:
3674 _Screen
._root
= self
._root
= _Root()
3675 self
._root
.title(_Screen
._title
)
3676 self
._root
.ondestroy(self
._destroy
)
3677 if _Screen
._canvas
is None:
3678 width
= _CFG
["width"]
3679 height
= _CFG
["height"]
3680 canvwidth
= _CFG
["canvwidth"]
3681 canvheight
= _CFG
["canvheight"]
3682 leftright
= _CFG
["leftright"]
3683 topbottom
= _CFG
["topbottom"]
3684 self
._root
.setupcanvas(width
, height
, canvwidth
, canvheight
)
3685 _Screen
._canvas
= self
._root
._getcanvas
()
3686 TurtleScreen
.__init
__(self
, _Screen
._canvas
)
3687 self
.setup(width
, height
, leftright
, topbottom
)
3689 def setup(self
, width
=_CFG
["width"], height
=_CFG
["height"],
3690 startx
=_CFG
["leftright"], starty
=_CFG
["topbottom"]):
3691 """ Set the size and position of the main window.
3694 width: as integer a size in pixels, as float a fraction of the screen.
3695 Default is 50% of screen.
3696 height: as integer the height in pixels, as float a fraction of the
3697 screen. Default is 75% of screen.
3698 startx: if positive, starting position in pixels from the left
3699 edge of the screen, if negative from the right edge
3700 Default, startx=None is to center window horizontally.
3701 starty: if positive, starting position in pixels from the top
3702 edge of the screen, if negative from the bottom edge
3703 Default, starty=None is to center window vertically.
3705 Examples (for a Screen instance named screen):
3706 >>> screen.setup (width=200, height=200, startx=0, starty=0)
3708 sets window to 200x200 pixels, in upper left of screen
3710 >>> screen.setup(width=.75, height=0.5, startx=None, starty=None)
3712 sets window to 75% of screen by 50% of screen and centers
3714 if not hasattr(self
._root
, "set_geometry"):
3716 sw
= self
._root
.win_width()
3717 sh
= self
._root
.win_height()
3718 if isinstance(width
, float) and 0 <= width
<= 1:
3721 startx
= (sw
- width
) / 2
3722 if isinstance(height
, float) and 0 <= height
<= 1:
3725 starty
= (sh
- height
) / 2
3726 self
._root
.set_geometry(width
, height
, startx
, starty
)
3729 def title(self
, titlestring
):
3730 """Set title of turtle-window
3733 titlestring -- a string, to appear in the titlebar of the
3734 turtle graphics window.
3736 This is a method of Screen-class. Not available for TurtleScreen-
3739 Example (for a Screen instance named screen):
3740 >>> screen.title("Welcome to the turtle-zoo!")
3742 if _Screen
._root
is not None:
3743 _Screen
._root
.title(titlestring
)
3744 _Screen
._title
= titlestring
3748 if root
is _Screen
._root
:
3750 Turtle
._screen
= None
3751 _Screen
._root
= None
3752 _Screen
._canvas
= None
3753 TurtleScreen
._RUNNING
= True
3757 """Shut the turtlegraphics window.
3759 Example (for a TurtleScreen instance named screen):
3764 def exitonclick(self
):
3765 """Go into mainloop until the mouse is clicked.
3769 Bind bye() method to mouseclick on TurtleScreen.
3770 If "using_IDLE" - value in configuration dictionary is False
3771 (default value), enter mainloop.
3772 If IDLE with -n switch (no subprocess) is used, this value should be
3773 set to True in turtle.cfg. In this case IDLE's mainloop
3774 is active also for the client script.
3776 This is a method of the Screen-class and not available for
3777 TurtleScreen instances.
3779 Example (for a Screen instance named screen):
3780 >>> screen.exitonclick()
3783 def exitGracefully(x
, y
):
3784 """Screen.bye() with two dummy-parameters"""
3786 self
.onclick(exitGracefully
)
3787 if _CFG
["using_IDLE"]:
3791 except AttributeError:
3795 class Turtle(RawTurtle
):
3796 """RawTurtle auto-crating (scrolled) canvas.
3798 When a Turtle object is created or a function derived from some
3799 Turtle method is called a TurtleScreen object is automatically created.
3805 shape
=_CFG
["shape"],
3806 undobuffersize
=_CFG
["undobuffersize"],
3807 visible
=_CFG
["visible"]):
3808 if Turtle
._screen
is None:
3809 Turtle
._screen
= Screen()
3810 RawTurtle
.__init
__(self
, Turtle
._screen
,
3812 undobuffersize
=undobuffersize
,
3818 """Create the 'anonymous' turtle if not already present."""
3819 if Turtle
._pen
is None:
3820 Turtle
._pen
= Turtle()
3824 """Create a TurtleScreen if not already present."""
3825 if Turtle
._screen
is None:
3826 Turtle
._screen
= Screen()
3827 return Turtle
._screen
3829 def write_docstringdict(filename
="turtle_docstringdict"):
3830 """Create and write docstring-dictionary to file.
3833 filename -- a string, used as filename
3834 default value is turtle_docstringdict
3836 Has to be called explicitely, (not used by the turtle-graphics classes)
3837 The docstring dictionary will be written to the Python script <filname>.py
3838 It is intended to serve as a template for translation of the docstrings
3839 into different languages.
3843 for methodname
in _tg_screen_functions
:
3844 key
= "_Screen."+methodname
3845 docsdict
[key
] = eval(key
).__doc
__
3846 for methodname
in _tg_turtle_functions
:
3847 key
= "Turtle."+methodname
3848 docsdict
[key
] = eval(key
).__doc
__
3850 f
= open("%s.py" % filename
,"w")
3851 keys
= sorted([x
for x
in docsdict
.keys()
3852 if x
.split('.')[1] not in _alias_list
])
3853 f
.write('docsdict = {\n\n')
3854 for key
in keys
[:-1]:
3855 f
.write('%s :\n' % repr(key
))
3856 f
.write(' """%s\n""",\n\n' % docsdict
[key
])
3858 f
.write('%s :\n' % repr(key
))
3859 f
.write(' """%s\n"""\n\n' % docsdict
[key
])
3863 def read_docstrings(lang
):
3864 """Read in docstrings from lang-specific docstring dictionary.
3866 Transfer docstrings, translated to lang, from a dictionary-file
3867 to the methods of classes Screen and Turtle and - in revised form -
3868 to the corresponding functions.
3870 modname
= "turtle_docstringdict_%(language)s" % {'language':lang
.lower()}
3871 module
= __import__(modname
)
3872 docsdict
= module
.docsdict
3873 for key
in docsdict
:
3875 # eval(key).im_func.__doc__ = docsdict[key]
3876 eval(key
).__doc
__ = docsdict
[key
]
3878 print("Bad docstring-entry: %s" % key
)
3880 _LANGUAGE
= _CFG
["language"]
3883 if _LANGUAGE
!= "english":
3884 read_docstrings(_LANGUAGE
)
3886 print("Cannot find docsdict for", _LANGUAGE
)
3888 print ("Unknown Error when trying to import %s-docstring-dictionary" %
3892 def getmethparlist(ob
):
3893 "Get strings describing the arguments for the given object"
3894 argText1
= argText2
= ""
3895 # bit of a hack for methods - turn it into a function
3896 # but we drop the "self" param.
3897 # Try and build one for Python defined functions
3899 counter
= ob
.__code
__.co_argcount
3900 items2
= list(ob
.__code
__.co_varnames
[argOffset
:counter
])
3901 realArgs
= ob
.__code
__.co_varnames
[argOffset
:counter
]
3902 defaults
= ob
.__defaults
__ or []
3903 defaults
= list(map(lambda name
: "=%s" % repr(name
), defaults
))
3904 defaults
= [""] * (len(realArgs
)-len(defaults
)) + defaults
3905 items1
= list(map(lambda arg
, dflt
: arg
+dflt
, realArgs
, defaults
))
3906 if ob
.__code
__.co_flags
& 0x4:
3907 items1
.append("*"+ob
.__code
__.co_varnames
[counter
])
3908 items2
.append("*"+ob
.__code
__.co_varnames
[counter
])
3910 if ob
.__code
__.co_flags
& 0x8:
3911 items1
.append("**"+ob
.__code
__.co_varnames
[counter
])
3912 items2
.append("**"+ob
.__code
__.co_varnames
[counter
])
3913 argText1
= ", ".join(items1
)
3914 argText1
= "(%s)" % argText1
3915 argText2
= ", ".join(items2
)
3916 argText2
= "(%s)" % argText2
3917 return argText1
, argText2
3919 def _turtle_docrevise(docstr
):
3920 """To reduce docstrings from RawTurtle class for functions
3925 turtlename
= _CFG
["exampleturtle"]
3926 newdocstr
= docstr
.replace("%s." % turtlename
,"")
3927 parexp
= re
.compile(r
' \(.+ %s\):' % turtlename
)
3928 newdocstr
= parexp
.sub(":", newdocstr
)
3931 def _screen_docrevise(docstr
):
3932 """To reduce docstrings from TurtleScreen class for functions
3937 screenname
= _CFG
["examplescreen"]
3938 newdocstr
= docstr
.replace("%s." % screenname
,"")
3939 parexp
= re
.compile(r
' \(.+ %s\):' % screenname
)
3940 newdocstr
= parexp
.sub(":", newdocstr
)
3943 ## The following mechanism makes all methods of RawTurtle and Turtle available
3944 ## as functions. So we can enhance, change, add, delete methods to these
3945 ## classes and do not need to change anything here.
3948 for methodname
in _tg_screen_functions
:
3949 pl1
, pl2
= getmethparlist(eval('_Screen.' + methodname
))
3951 print(">>>>>>", pl1
, pl2
)
3953 defstr
= ("def %(key)s%(pl1)s: return _getscreen().%(key)s%(pl2)s" %
3954 {'key':methodname
, 'pl1':pl1
, 'pl2':pl2
})
3956 eval(methodname
).__doc
__ = _screen_docrevise(eval('_Screen.'+methodname
).__doc
__)
3958 for methodname
in _tg_turtle_functions
:
3959 pl1
, pl2
= getmethparlist(eval('Turtle.' + methodname
))
3961 print(">>>>>>", pl1
, pl2
)
3963 defstr
= ("def %(key)s%(pl1)s: return _getpen().%(key)s%(pl2)s" %
3964 {'key':methodname
, 'pl1':pl1
, 'pl2':pl2
})
3966 eval(methodname
).__doc
__ = _turtle_docrevise(eval('Turtle.'+methodname
).__doc
__)
3971 if __name__
== "__main__":
3979 """Demo of old turtle.py - module"""
3985 # draw 3 squares; the last filled
4001 # move out of the way
4011 write("startstart", 1)
4032 """Demo of some new features."""
4036 setheading(towards(0, 0))
4037 radius
= distance(0, 0)/2.0
4042 write("wait a moment...")
4043 while undobufferentries():
4052 for i
in range(-2, 16):
4055 fillcolor(255-15*i
, 0, 15*i
)
4062 speed((speed()+1)%12)
4070 color("red","yellow")
4086 tri
.resizemode("auto")
4088 turtle
.resizemode("auto")
4089 turtle
.shape("turtle")
4094 turtle
.goto(280, 40)
4098 turtle
.color("blue","orange")
4101 setheading(towards(turtle
))
4103 while tri
.distance(turtle
) > 4:
4106 tri
.setheading(tri
.towards(turtle
))
4113 tri
.write("CAUGHT! ", font
=("Arial", 16, "bold"), align
="right")
4114 tri
.pencolor("black")
4117 def baba(xdummy
, ydummy
):
4123 while undobufferentries():
4127 tri
.write(" Click me!", font
= ("Courier", 12, "bold") )
4128 tri
.onclick(baba
, 1)