PageRenderTime 58ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/lib-python/2.7/lib-tk/turtle.py

https://bitbucket.org/evelyn559/pypy
Python | 4039 lines | 3835 code | 29 blank | 175 comment | 29 complexity | 3679dedad2f61079ef0cbfa77e0ed1e7 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. #
  2. # turtle.py: a Tkinter based turtle graphics module for Python
  3. # Version 1.0.1 - 24. 9. 2009
  4. #
  5. # Copyright (C) 2006 - 2010 Gregor Lingl
  6. # email: glingl@aon.at
  7. #
  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.
  11. #
  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:
  15. #
  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.
  23. """
  24. Turtle graphics is a popular way for introducing programming to
  25. kids. It was part of the original Logo programming language developed
  26. by Wally Feurzig and Seymour Papert in 1966.
  27. Imagine a robotic turtle starting at (0, 0) in the x-y plane. Give it
  28. the command turtle.forward(15), and it moves (on-screen!) 15 pixels in
  29. the direction it is facing, drawing a line as it moves. Give it the
  30. command turtle.left(25), and it rotates in-place 25 degrees clockwise.
  31. By combining together these and similar commands, intricate shapes and
  32. pictures can easily be drawn.
  33. ----- turtle.py
  34. This module is an extended reimplementation of turtle.py from the
  35. Python standard distribution up to Python 2.5. (See: http://www.python.org)
  36. It tries to keep the merits of turtle.py and to be (nearly) 100%
  37. compatible with it. This means in the first place to enable the
  38. learning programmer to use all the commands, classes and methods
  39. interactively when using the module from within IDLE run with
  40. the -n switch.
  41. Roughly it has the following features added:
  42. - Better animation of the turtle movements, especially of turning the
  43. turtle. So the turtles can more easily be used as a visual feedback
  44. instrument by the (beginning) programmer.
  45. - Different turtle shapes, gif-images as turtle shapes, user defined
  46. and user controllable turtle shapes, among them compound
  47. (multicolored) shapes. Turtle shapes can be stretched and tilted, which
  48. makes turtles very versatile geometrical objects.
  49. - Fine control over turtle movement and screen updates via delay(),
  50. and enhanced tracer() and speed() methods.
  51. - Aliases for the most commonly used commands, like fd for forward etc.,
  52. following the early Logo traditions. This reduces the boring work of
  53. typing long sequences of commands, which often occur in a natural way
  54. when kids try to program fancy pictures on their first encounter with
  55. turtle graphics.
  56. - Turtles now have an undo()-method with configurable undo-buffer.
  57. - Some simple commands/methods for creating event driven programs
  58. (mouse-, key-, timer-events). Especially useful for programming games.
  59. - A scrollable Canvas class. The default scrollable Canvas can be
  60. extended interactively as needed while playing around with the turtle(s).
  61. - A TurtleScreen class with methods controlling background color or
  62. background image, window and canvas size and other properties of the
  63. TurtleScreen.
  64. - There is a method, setworldcoordinates(), to install a user defined
  65. coordinate-system for the TurtleScreen.
  66. - The implementation uses a 2-vector class named Vec2D, derived from tuple.
  67. This class is public, so it can be imported by the application programmer,
  68. which makes certain types of computations very natural and compact.
  69. - Appearance of the TurtleScreen and the Turtles at startup/import can be
  70. configured by means of a turtle.cfg configuration file.
  71. The default configuration mimics the appearance of the old turtle module.
  72. - If configured appropriately the module reads in docstrings from a docstring
  73. dictionary in some different language, supplied separately and replaces
  74. the English ones by those read in. There is a utility function
  75. write_docstringdict() to write a dictionary with the original (English)
  76. docstrings to disc, so it can serve as a template for translations.
  77. Behind the scenes there are some features included with possible
  78. extensions in in mind. These will be commented and documented elsewhere.
  79. """
  80. _ver = "turtle 1.0b1 - for Python 2.6 - 30. 5. 2008, 18:08"
  81. #print _ver
  82. import Tkinter as TK
  83. import types
  84. import math
  85. import time
  86. import os
  87. from os.path import isfile, split, join
  88. from copy import deepcopy
  89. from math import * ## for compatibility with old turtle module
  90. _tg_classes = ['ScrolledCanvas', 'TurtleScreen', 'Screen',
  91. 'RawTurtle', 'Turtle', 'RawPen', 'Pen', 'Shape', 'Vec2D']
  92. _tg_screen_functions = ['addshape', 'bgcolor', 'bgpic', 'bye',
  93. 'clearscreen', 'colormode', 'delay', 'exitonclick', 'getcanvas',
  94. 'getshapes', 'listen', 'mode', 'onkey', 'onscreenclick', 'ontimer',
  95. 'register_shape', 'resetscreen', 'screensize', 'setup',
  96. 'setworldcoordinates', 'title', 'tracer', 'turtles', 'update',
  97. 'window_height', 'window_width']
  98. _tg_turtle_functions = ['back', 'backward', 'begin_fill', 'begin_poly', 'bk',
  99. 'circle', 'clear', 'clearstamp', 'clearstamps', 'clone', 'color',
  100. 'degrees', 'distance', 'dot', 'down', 'end_fill', 'end_poly', 'fd',
  101. 'fill', 'fillcolor', 'forward', 'get_poly', 'getpen', 'getscreen',
  102. 'getturtle', 'goto', 'heading', 'hideturtle', 'home', 'ht', 'isdown',
  103. 'isvisible', 'left', 'lt', 'onclick', 'ondrag', 'onrelease', 'pd',
  104. 'pen', 'pencolor', 'pendown', 'pensize', 'penup', 'pos', 'position',
  105. 'pu', 'radians', 'right', 'reset', 'resizemode', 'rt',
  106. 'seth', 'setheading', 'setpos', 'setposition', 'settiltangle',
  107. 'setundobuffer', 'setx', 'sety', 'shape', 'shapesize', 'showturtle',
  108. 'speed', 'st', 'stamp', 'tilt', 'tiltangle', 'towards', 'tracer',
  109. 'turtlesize', 'undo', 'undobufferentries', 'up', 'width',
  110. 'window_height', 'window_width', 'write', 'xcor', 'ycor']
  111. _tg_utilities = ['write_docstringdict', 'done', 'mainloop']
  112. _math_functions = ['acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'cosh',
  113. 'e', 'exp', 'fabs', 'floor', 'fmod', 'frexp', 'hypot', 'ldexp', 'log',
  114. 'log10', 'modf', 'pi', 'pow', 'sin', 'sinh', 'sqrt', 'tan', 'tanh']
  115. __all__ = (_tg_classes + _tg_screen_functions + _tg_turtle_functions +
  116. _tg_utilities + _math_functions)
  117. _alias_list = ['addshape', 'backward', 'bk', 'fd', 'ht', 'lt', 'pd', 'pos',
  118. 'pu', 'rt', 'seth', 'setpos', 'setposition', 'st',
  119. 'turtlesize', 'up', 'width']
  120. _CFG = {"width" : 0.5, # Screen
  121. "height" : 0.75,
  122. "canvwidth" : 400,
  123. "canvheight": 300,
  124. "leftright": None,
  125. "topbottom": None,
  126. "mode": "standard", # TurtleScreen
  127. "colormode": 1.0,
  128. "delay": 10,
  129. "undobuffersize": 1000, # RawTurtle
  130. "shape": "classic",
  131. "pencolor" : "black",
  132. "fillcolor" : "black",
  133. "resizemode" : "noresize",
  134. "visible" : True,
  135. "language": "english", # docstrings
  136. "exampleturtle": "turtle",
  137. "examplescreen": "screen",
  138. "title": "Python Turtle Graphics",
  139. "using_IDLE": False
  140. }
  141. ##print "cwd:", os.getcwd()
  142. ##print "__file__:", __file__
  143. ##
  144. ##def show(dictionary):
  145. ## print "=========================="
  146. ## for key in sorted(dictionary.keys()):
  147. ## print key, ":", dictionary[key]
  148. ## print "=========================="
  149. ## print
  150. def config_dict(filename):
  151. """Convert content of config-file into dictionary."""
  152. f = open(filename, "r")
  153. cfglines = f.readlines()
  154. f.close()
  155. cfgdict = {}
  156. for line in cfglines:
  157. line = line.strip()
  158. if not line or line.startswith("#"):
  159. continue
  160. try:
  161. key, value = line.split("=")
  162. except:
  163. print "Bad line in config-file %s:\n%s" % (filename,line)
  164. continue
  165. key = key.strip()
  166. value = value.strip()
  167. if value in ["True", "False", "None", "''", '""']:
  168. value = eval(value)
  169. else:
  170. try:
  171. if "." in value:
  172. value = float(value)
  173. else:
  174. value = int(value)
  175. except:
  176. pass # value need not be converted
  177. cfgdict[key] = value
  178. return cfgdict
  179. def readconfig(cfgdict):
  180. """Read config-files, change configuration-dict accordingly.
  181. If there is a turtle.cfg file in the current working directory,
  182. read it from there. If this contains an importconfig-value,
  183. say 'myway', construct filename turtle_mayway.cfg else use
  184. turtle.cfg and read it from the import-directory, where
  185. turtle.py is located.
  186. Update configuration dictionary first according to config-file,
  187. in the import directory, then according to config-file in the
  188. current working directory.
  189. If no config-file is found, the default configuration is used.
  190. """
  191. default_cfg = "turtle.cfg"
  192. cfgdict1 = {}
  193. cfgdict2 = {}
  194. if isfile(default_cfg):
  195. cfgdict1 = config_dict(default_cfg)
  196. #print "1. Loading config-file %s from: %s" % (default_cfg, os.getcwd())
  197. if "importconfig" in cfgdict1:
  198. default_cfg = "turtle_%s.cfg" % cfgdict1["importconfig"]
  199. try:
  200. head, tail = split(__file__)
  201. cfg_file2 = join(head, default_cfg)
  202. except:
  203. cfg_file2 = ""
  204. if isfile(cfg_file2):
  205. #print "2. Loading config-file %s:" % cfg_file2
  206. cfgdict2 = config_dict(cfg_file2)
  207. ## show(_CFG)
  208. ## show(cfgdict2)
  209. _CFG.update(cfgdict2)
  210. ## show(_CFG)
  211. ## show(cfgdict1)
  212. _CFG.update(cfgdict1)
  213. ## show(_CFG)
  214. try:
  215. readconfig(_CFG)
  216. except:
  217. print "No configfile read, reason unknown"
  218. class Vec2D(tuple):
  219. """A 2 dimensional vector class, used as a helper class
  220. for implementing turtle graphics.
  221. May be useful for turtle graphics programs also.
  222. Derived from tuple, so a vector is a tuple!
  223. Provides (for a, b vectors, k number):
  224. a+b vector addition
  225. a-b vector subtraction
  226. a*b inner product
  227. k*a and a*k multiplication with scalar
  228. |a| absolute value of a
  229. a.rotate(angle) rotation
  230. """
  231. def __new__(cls, x, y):
  232. return tuple.__new__(cls, (x, y))
  233. def __add__(self, other):
  234. return Vec2D(self[0]+other[0], self[1]+other[1])
  235. def __mul__(self, other):
  236. if isinstance(other, Vec2D):
  237. return self[0]*other[0]+self[1]*other[1]
  238. return Vec2D(self[0]*other, self[1]*other)
  239. def __rmul__(self, other):
  240. if isinstance(other, int) or isinstance(other, float):
  241. return Vec2D(self[0]*other, self[1]*other)
  242. def __sub__(self, other):
  243. return Vec2D(self[0]-other[0], self[1]-other[1])
  244. def __neg__(self):
  245. return Vec2D(-self[0], -self[1])
  246. def __abs__(self):
  247. return (self[0]**2 + self[1]**2)**0.5
  248. def rotate(self, angle):
  249. """rotate self counterclockwise by angle
  250. """
  251. perp = Vec2D(-self[1], self[0])
  252. angle = angle * math.pi / 180.0
  253. c, s = math.cos(angle), math.sin(angle)
  254. return Vec2D(self[0]*c+perp[0]*s, self[1]*c+perp[1]*s)
  255. def __getnewargs__(self):
  256. return (self[0], self[1])
  257. def __repr__(self):
  258. return "(%.2f,%.2f)" % self
  259. ##############################################################################
  260. ### From here up to line : Tkinter - Interface for turtle.py ###
  261. ### May be replaced by an interface to some different graphics toolkit ###
  262. ##############################################################################
  263. ## helper functions for Scrolled Canvas, to forward Canvas-methods
  264. ## to ScrolledCanvas class
  265. def __methodDict(cls, _dict):
  266. """helper function for Scrolled Canvas"""
  267. baseList = list(cls.__bases__)
  268. baseList.reverse()
  269. for _super in baseList:
  270. __methodDict(_super, _dict)
  271. for key, value in cls.__dict__.items():
  272. if type(value) == types.FunctionType:
  273. _dict[key] = value
  274. def __methods(cls):
  275. """helper function for Scrolled Canvas"""
  276. _dict = {}
  277. __methodDict(cls, _dict)
  278. return _dict.keys()
  279. __stringBody = (
  280. 'def %(method)s(self, *args, **kw): return ' +
  281. 'self.%(attribute)s.%(method)s(*args, **kw)')
  282. def __forwardmethods(fromClass, toClass, toPart, exclude = ()):
  283. """Helper functions for Scrolled Canvas, used to forward
  284. ScrolledCanvas-methods to Tkinter.Canvas class.
  285. """
  286. _dict = {}
  287. __methodDict(toClass, _dict)
  288. for ex in _dict.keys():
  289. if ex[:1] == '_' or ex[-1:] == '_':
  290. del _dict[ex]
  291. for ex in exclude:
  292. if ex in _dict:
  293. del _dict[ex]
  294. for ex in __methods(fromClass):
  295. if ex in _dict:
  296. del _dict[ex]
  297. for method, func in _dict.items():
  298. d = {'method': method, 'func': func}
  299. if type(toPart) == types.StringType:
  300. execString = \
  301. __stringBody % {'method' : method, 'attribute' : toPart}
  302. exec execString in d
  303. fromClass.__dict__[method] = d[method]
  304. class ScrolledCanvas(TK.Frame):
  305. """Modeled after the scrolled canvas class from Grayons's Tkinter book.
  306. Used as the default canvas, which pops up automatically when
  307. using turtle graphics functions or the Turtle class.
  308. """
  309. def __init__(self, master, width=500, height=350,
  310. canvwidth=600, canvheight=500):
  311. TK.Frame.__init__(self, master, width=width, height=height)
  312. self._rootwindow = self.winfo_toplevel()
  313. self.width, self.height = width, height
  314. self.canvwidth, self.canvheight = canvwidth, canvheight
  315. self.bg = "white"
  316. self._canvas = TK.Canvas(master, width=width, height=height,
  317. bg=self.bg, relief=TK.SUNKEN, borderwidth=2)
  318. self.hscroll = TK.Scrollbar(master, command=self._canvas.xview,
  319. orient=TK.HORIZONTAL)
  320. self.vscroll = TK.Scrollbar(master, command=self._canvas.yview)
  321. self._canvas.configure(xscrollcommand=self.hscroll.set,
  322. yscrollcommand=self.vscroll.set)
  323. self.rowconfigure(0, weight=1, minsize=0)
  324. self.columnconfigure(0, weight=1, minsize=0)
  325. self._canvas.grid(padx=1, in_ = self, pady=1, row=0,
  326. column=0, rowspan=1, columnspan=1, sticky='news')
  327. self.vscroll.grid(padx=1, in_ = self, pady=1, row=0,
  328. column=1, rowspan=1, columnspan=1, sticky='news')
  329. self.hscroll.grid(padx=1, in_ = self, pady=1, row=1,
  330. column=0, rowspan=1, columnspan=1, sticky='news')
  331. self.reset()
  332. self._rootwindow.bind('<Configure>', self.onResize)
  333. def reset(self, canvwidth=None, canvheight=None, bg = None):
  334. """Adjust canvas and scrollbars according to given canvas size."""
  335. if canvwidth:
  336. self.canvwidth = canvwidth
  337. if canvheight:
  338. self.canvheight = canvheight
  339. if bg:
  340. self.bg = bg
  341. self._canvas.config(bg=bg,
  342. scrollregion=(-self.canvwidth//2, -self.canvheight//2,
  343. self.canvwidth//2, self.canvheight//2))
  344. self._canvas.xview_moveto(0.5*(self.canvwidth - self.width + 30) /
  345. self.canvwidth)
  346. self._canvas.yview_moveto(0.5*(self.canvheight- self.height + 30) /
  347. self.canvheight)
  348. self.adjustScrolls()
  349. def adjustScrolls(self):
  350. """ Adjust scrollbars according to window- and canvas-size.
  351. """
  352. cwidth = self._canvas.winfo_width()
  353. cheight = self._canvas.winfo_height()
  354. self._canvas.xview_moveto(0.5*(self.canvwidth-cwidth)/self.canvwidth)
  355. self._canvas.yview_moveto(0.5*(self.canvheight-cheight)/self.canvheight)
  356. if cwidth < self.canvwidth or cheight < self.canvheight:
  357. self.hscroll.grid(padx=1, in_ = self, pady=1, row=1,
  358. column=0, rowspan=1, columnspan=1, sticky='news')
  359. self.vscroll.grid(padx=1, in_ = self, pady=1, row=0,
  360. column=1, rowspan=1, columnspan=1, sticky='news')
  361. else:
  362. self.hscroll.grid_forget()
  363. self.vscroll.grid_forget()
  364. def onResize(self, event):
  365. """self-explanatory"""
  366. self.adjustScrolls()
  367. def bbox(self, *args):
  368. """ 'forward' method, which canvas itself has inherited...
  369. """
  370. return self._canvas.bbox(*args)
  371. def cget(self, *args, **kwargs):
  372. """ 'forward' method, which canvas itself has inherited...
  373. """
  374. return self._canvas.cget(*args, **kwargs)
  375. def config(self, *args, **kwargs):
  376. """ 'forward' method, which canvas itself has inherited...
  377. """
  378. self._canvas.config(*args, **kwargs)
  379. def bind(self, *args, **kwargs):
  380. """ 'forward' method, which canvas itself has inherited...
  381. """
  382. self._canvas.bind(*args, **kwargs)
  383. def unbind(self, *args, **kwargs):
  384. """ 'forward' method, which canvas itself has inherited...
  385. """
  386. self._canvas.unbind(*args, **kwargs)
  387. def focus_force(self):
  388. """ 'forward' method, which canvas itself has inherited...
  389. """
  390. self._canvas.focus_force()
  391. __forwardmethods(ScrolledCanvas, TK.Canvas, '_canvas')
  392. class _Root(TK.Tk):
  393. """Root class for Screen based on Tkinter."""
  394. def __init__(self):
  395. TK.Tk.__init__(self)
  396. def setupcanvas(self, width, height, cwidth, cheight):
  397. self._canvas = ScrolledCanvas(self, width, height, cwidth, cheight)
  398. self._canvas.pack(expand=1, fill="both")
  399. def _getcanvas(self):
  400. return self._canvas
  401. def set_geometry(self, width, height, startx, starty):
  402. self.geometry("%dx%d%+d%+d"%(width, height, startx, starty))
  403. def ondestroy(self, destroy):
  404. self.wm_protocol("WM_DELETE_WINDOW", destroy)
  405. def win_width(self):
  406. return self.winfo_screenwidth()
  407. def win_height(self):
  408. return self.winfo_screenheight()
  409. Canvas = TK.Canvas
  410. class TurtleScreenBase(object):
  411. """Provide the basic graphics functionality.
  412. Interface between Tkinter and turtle.py.
  413. To port turtle.py to some different graphics toolkit
  414. a corresponding TurtleScreenBase class has to be implemented.
  415. """
  416. @staticmethod
  417. def _blankimage():
  418. """return a blank image object
  419. """
  420. img = TK.PhotoImage(width=1, height=1)
  421. img.blank()
  422. return img
  423. @staticmethod
  424. def _image(filename):
  425. """return an image object containing the
  426. imagedata from a gif-file named filename.
  427. """
  428. return TK.PhotoImage(file=filename)
  429. def __init__(self, cv):
  430. self.cv = cv
  431. if isinstance(cv, ScrolledCanvas):
  432. w = self.cv.canvwidth
  433. h = self.cv.canvheight
  434. else: # expected: ordinary TK.Canvas
  435. w = int(self.cv.cget("width"))
  436. h = int(self.cv.cget("height"))
  437. self.cv.config(scrollregion = (-w//2, -h//2, w//2, h//2 ))
  438. self.canvwidth = w
  439. self.canvheight = h
  440. self.xscale = self.yscale = 1.0
  441. def _createpoly(self):
  442. """Create an invisible polygon item on canvas self.cv)
  443. """
  444. return self.cv.create_polygon((0, 0, 0, 0, 0, 0), fill="", outline="")
  445. def _drawpoly(self, polyitem, coordlist, fill=None,
  446. outline=None, width=None, top=False):
  447. """Configure polygonitem polyitem according to provided
  448. arguments:
  449. coordlist is sequence of coordinates
  450. fill is filling color
  451. outline is outline color
  452. top is a boolean value, which specifies if polyitem
  453. will be put on top of the canvas' displaylist so it
  454. will not be covered by other items.
  455. """
  456. cl = []
  457. for x, y in coordlist:
  458. cl.append(x * self.xscale)
  459. cl.append(-y * self.yscale)
  460. self.cv.coords(polyitem, *cl)
  461. if fill is not None:
  462. self.cv.itemconfigure(polyitem, fill=fill)
  463. if outline is not None:
  464. self.cv.itemconfigure(polyitem, outline=outline)
  465. if width is not None:
  466. self.cv.itemconfigure(polyitem, width=width)
  467. if top:
  468. self.cv.tag_raise(polyitem)
  469. def _createline(self):
  470. """Create an invisible line item on canvas self.cv)
  471. """
  472. return self.cv.create_line(0, 0, 0, 0, fill="", width=2,
  473. capstyle = TK.ROUND)
  474. def _drawline(self, lineitem, coordlist=None,
  475. fill=None, width=None, top=False):
  476. """Configure lineitem according to provided arguments:
  477. coordlist is sequence of coordinates
  478. fill is drawing color
  479. width is width of drawn line.
  480. top is a boolean value, which specifies if polyitem
  481. will be put on top of the canvas' displaylist so it
  482. will not be covered by other items.
  483. """
  484. if coordlist is not None:
  485. cl = []
  486. for x, y in coordlist:
  487. cl.append(x * self.xscale)
  488. cl.append(-y * self.yscale)
  489. self.cv.coords(lineitem, *cl)
  490. if fill is not None:
  491. self.cv.itemconfigure(lineitem, fill=fill)
  492. if width is not None:
  493. self.cv.itemconfigure(lineitem, width=width)
  494. if top:
  495. self.cv.tag_raise(lineitem)
  496. def _delete(self, item):
  497. """Delete graphics item from canvas.
  498. If item is"all" delete all graphics items.
  499. """
  500. self.cv.delete(item)
  501. def _update(self):
  502. """Redraw graphics items on canvas
  503. """
  504. self.cv.update()
  505. def _delay(self, delay):
  506. """Delay subsequent canvas actions for delay ms."""
  507. self.cv.after(delay)
  508. def _iscolorstring(self, color):
  509. """Check if the string color is a legal Tkinter color string.
  510. """
  511. try:
  512. rgb = self.cv.winfo_rgb(color)
  513. ok = True
  514. except TK.TclError:
  515. ok = False
  516. return ok
  517. def _bgcolor(self, color=None):
  518. """Set canvas' backgroundcolor if color is not None,
  519. else return backgroundcolor."""
  520. if color is not None:
  521. self.cv.config(bg = color)
  522. self._update()
  523. else:
  524. return self.cv.cget("bg")
  525. def _write(self, pos, txt, align, font, pencolor):
  526. """Write txt at pos in canvas with specified font
  527. and color.
  528. Return text item and x-coord of right bottom corner
  529. of text's bounding box."""
  530. x, y = pos
  531. x = x * self.xscale
  532. y = y * self.yscale
  533. anchor = {"left":"sw", "center":"s", "right":"se" }
  534. item = self.cv.create_text(x-1, -y, text = txt, anchor = anchor[align],
  535. fill = pencolor, font = font)
  536. x0, y0, x1, y1 = self.cv.bbox(item)
  537. self.cv.update()
  538. return item, x1-1
  539. ## def _dot(self, pos, size, color):
  540. ## """may be implemented for some other graphics toolkit"""
  541. def _onclick(self, item, fun, num=1, add=None):
  542. """Bind fun to mouse-click event on turtle.
  543. fun must be a function with two arguments, the coordinates
  544. of the clicked point on the canvas.
  545. num, the number of the mouse-button defaults to 1
  546. """
  547. if fun is None:
  548. self.cv.tag_unbind(item, "<Button-%s>" % num)
  549. else:
  550. def eventfun(event):
  551. x, y = (self.cv.canvasx(event.x)/self.xscale,
  552. -self.cv.canvasy(event.y)/self.yscale)
  553. fun(x, y)
  554. self.cv.tag_bind(item, "<Button-%s>" % num, eventfun, add)
  555. def _onrelease(self, item, fun, num=1, add=None):
  556. """Bind fun to mouse-button-release event on turtle.
  557. fun must be a function with two arguments, the coordinates
  558. of the point on the canvas where mouse button is released.
  559. num, the number of the mouse-button defaults to 1
  560. If a turtle is clicked, first _onclick-event will be performed,
  561. then _onscreensclick-event.
  562. """
  563. if fun is None:
  564. self.cv.tag_unbind(item, "<Button%s-ButtonRelease>" % num)
  565. else:
  566. def eventfun(event):
  567. x, y = (self.cv.canvasx(event.x)/self.xscale,
  568. -self.cv.canvasy(event.y)/self.yscale)
  569. fun(x, y)
  570. self.cv.tag_bind(item, "<Button%s-ButtonRelease>" % num,
  571. eventfun, add)
  572. def _ondrag(self, item, fun, num=1, add=None):
  573. """Bind fun to mouse-move-event (with pressed mouse button) on turtle.
  574. fun must be a function with two arguments, the coordinates of the
  575. actual mouse position on the canvas.
  576. num, the number of the mouse-button defaults to 1
  577. Every sequence of mouse-move-events on a turtle is preceded by a
  578. mouse-click event on that turtle.
  579. """
  580. if fun is None:
  581. self.cv.tag_unbind(item, "<Button%s-Motion>" % num)
  582. else:
  583. def eventfun(event):
  584. try:
  585. x, y = (self.cv.canvasx(event.x)/self.xscale,
  586. -self.cv.canvasy(event.y)/self.yscale)
  587. fun(x, y)
  588. except:
  589. pass
  590. self.cv.tag_bind(item, "<Button%s-Motion>" % num, eventfun, add)
  591. def _onscreenclick(self, fun, num=1, add=None):
  592. """Bind fun to mouse-click event on canvas.
  593. fun must be a function with two arguments, the coordinates
  594. of the clicked point on the canvas.
  595. num, the number of the mouse-button defaults to 1
  596. If a turtle is clicked, first _onclick-event will be performed,
  597. then _onscreensclick-event.
  598. """
  599. if fun is None:
  600. self.cv.unbind("<Button-%s>" % num)
  601. else:
  602. def eventfun(event):
  603. x, y = (self.cv.canvasx(event.x)/self.xscale,
  604. -self.cv.canvasy(event.y)/self.yscale)
  605. fun(x, y)
  606. self.cv.bind("<Button-%s>" % num, eventfun, add)
  607. def _onkey(self, fun, key):
  608. """Bind fun to key-release event of key.
  609. Canvas must have focus. See method listen
  610. """
  611. if fun is None:
  612. self.cv.unbind("<KeyRelease-%s>" % key, None)
  613. else:
  614. def eventfun(event):
  615. fun()
  616. self.cv.bind("<KeyRelease-%s>" % key, eventfun)
  617. def _listen(self):
  618. """Set focus on canvas (in order to collect key-events)
  619. """
  620. self.cv.focus_force()
  621. def _ontimer(self, fun, t):
  622. """Install a timer, which calls fun after t milliseconds.
  623. """
  624. if t == 0:
  625. self.cv.after_idle(fun)
  626. else:
  627. self.cv.after(t, fun)
  628. def _createimage(self, image):
  629. """Create and return image item on canvas.
  630. """
  631. return self.cv.create_image(0, 0, image=image)
  632. def _drawimage(self, item, (x, y), image):
  633. """Configure image item as to draw image object
  634. at position (x,y) on canvas)
  635. """
  636. self.cv.coords(item, (x * self.xscale, -y * self.yscale))
  637. self.cv.itemconfig(item, image=image)
  638. def _setbgpic(self, item, image):
  639. """Configure image item as to draw image object
  640. at center of canvas. Set item to the first item
  641. in the displaylist, so it will be drawn below
  642. any other item ."""
  643. self.cv.itemconfig(item, image=image)
  644. self.cv.tag_lower(item)
  645. def _type(self, item):
  646. """Return 'line' or 'polygon' or 'image' depending on
  647. type of item.
  648. """
  649. return self.cv.type(item)
  650. def _pointlist(self, item):
  651. """returns list of coordinate-pairs of points of item
  652. Example (for insiders):
  653. >>> from turtle import *
  654. >>> getscreen()._pointlist(getturtle().turtle._item)
  655. [(0.0, 9.9999999999999982), (0.0, -9.9999999999999982),
  656. (9.9999999999999982, 0.0)]
  657. >>> """
  658. cl = self.cv.coords(item)
  659. pl = [(cl[i], -cl[i+1]) for i in range(0, len(cl), 2)]
  660. return pl
  661. def _setscrollregion(self, srx1, sry1, srx2, sry2):
  662. self.cv.config(scrollregion=(srx1, sry1, srx2, sry2))
  663. def _rescale(self, xscalefactor, yscalefactor):
  664. items = self.cv.find_all()
  665. for item in items:
  666. coordinates = self.cv.coords(item)
  667. newcoordlist = []
  668. while coordinates:
  669. x, y = coordinates[:2]
  670. newcoordlist.append(x * xscalefactor)
  671. newcoordlist.append(y * yscalefactor)
  672. coordinates = coordinates[2:]
  673. self.cv.coords(item, *newcoordlist)
  674. def _resize(self, canvwidth=None, canvheight=None, bg=None):
  675. """Resize the canvas the turtles are drawing on. Does
  676. not alter the drawing window.
  677. """
  678. # needs amendment
  679. if not isinstance(self.cv, ScrolledCanvas):
  680. return self.canvwidth, self.canvheight
  681. if canvwidth is canvheight is bg is None:
  682. return self.cv.canvwidth, self.cv.canvheight
  683. if canvwidth is not None:
  684. self.canvwidth = canvwidth
  685. if canvheight is not None:
  686. self.canvheight = canvheight
  687. self.cv.reset(canvwidth, canvheight, bg)
  688. def _window_size(self):
  689. """ Return the width and height of the turtle window.
  690. """
  691. width = self.cv.winfo_width()
  692. if width <= 1: # the window isn't managed by a geometry manager
  693. width = self.cv['width']
  694. height = self.cv.winfo_height()
  695. if height <= 1: # the window isn't managed by a geometry manager
  696. height = self.cv['height']
  697. return width, height
  698. ##############################################################################
  699. ### End of Tkinter - interface ###
  700. ##############################################################################
  701. class Terminator (Exception):
  702. """Will be raised in TurtleScreen.update, if _RUNNING becomes False.
  703. Thus stops execution of turtle graphics script. Main purpose: use in
  704. in the Demo-Viewer turtle.Demo.py.
  705. """
  706. pass
  707. class TurtleGraphicsError(Exception):
  708. """Some TurtleGraphics Error
  709. """
  710. class Shape(object):
  711. """Data structure modeling shapes.
  712. attribute _type is one of "polygon", "image", "compound"
  713. attribute _data is - depending on _type a poygon-tuple,
  714. an image or a list constructed using the addcomponent method.
  715. """
  716. def __init__(self, type_, data=None):
  717. self._type = type_
  718. if type_ == "polygon":
  719. if isinstance(data, list):
  720. data = tuple(data)
  721. elif type_ == "image":
  722. if isinstance(data, str):
  723. if data.lower().endswith(".gif") and isfile(data):
  724. data = TurtleScreen._image(data)
  725. # else data assumed to be Photoimage
  726. elif type_ == "compound":
  727. data = []
  728. else:
  729. raise TurtleGraphicsError("There is no shape type %s" % type_)
  730. self._data = data
  731. def addcomponent(self, poly, fill, outline=None):
  732. """Add component to a shape of type compound.
  733. Arguments: poly is a polygon, i. e. a tuple of number pairs.
  734. fill is the fillcolor of the component,
  735. outline is the outline color of the component.
  736. call (for a Shapeobject namend s):
  737. -- s.addcomponent(((0,0), (10,10), (-10,10)), "red", "blue")
  738. Example:
  739. >>> poly = ((0,0),(10,-5),(0,10),(-10,-5))
  740. >>> s = Shape("compound")
  741. >>> s.addcomponent(poly, "red", "blue")
  742. ### .. add more components and then use register_shape()
  743. """
  744. if self._type != "compound":
  745. raise TurtleGraphicsError("Cannot add component to %s Shape"
  746. % self._type)
  747. if outline is None:
  748. outline = fill
  749. self._data.append([poly, fill, outline])
  750. class Tbuffer(object):
  751. """Ring buffer used as undobuffer for RawTurtle objects."""
  752. def __init__(self, bufsize=10):
  753. self.bufsize = bufsize
  754. self.buffer = [[None]] * bufsize
  755. self.ptr = -1
  756. self.cumulate = False
  757. def reset(self, bufsize=None):
  758. if bufsize is None:
  759. for i in range(self.bufsize):
  760. self.buffer[i] = [None]
  761. else:
  762. self.bufsize = bufsize
  763. self.buffer = [[None]] * bufsize
  764. self.ptr = -1
  765. def push(self, item):
  766. if self.bufsize > 0:
  767. if not self.cumulate:
  768. self.ptr = (self.ptr + 1) % self.bufsize
  769. self.buffer[self.ptr] = item
  770. else:
  771. self.buffer[self.ptr].append(item)
  772. def pop(self):
  773. if self.bufsize > 0:
  774. item = self.buffer[self.ptr]
  775. if item is None:
  776. return None
  777. else:
  778. self.buffer[self.ptr] = [None]
  779. self.ptr = (self.ptr - 1) % self.bufsize
  780. return (item)
  781. def nr_of_items(self):
  782. return self.bufsize - self.buffer.count([None])
  783. def __repr__(self):
  784. return str(self.buffer) + " " + str(self.ptr)
  785. class TurtleScreen(TurtleScreenBase):
  786. """Provides screen oriented methods like setbg etc.
  787. Only relies upon the methods of TurtleScreenBase and NOT
  788. upon components of the underlying graphics toolkit -
  789. which is Tkinter in this case.
  790. """
  791. # _STANDARD_DELAY = 5
  792. _RUNNING = True
  793. def __init__(self, cv, mode=_CFG["mode"],
  794. colormode=_CFG["colormode"], delay=_CFG["delay"]):
  795. self._shapes = {
  796. "arrow" : Shape("polygon", ((-10,0), (10,0), (0,10))),
  797. "turtle" : Shape("polygon", ((0,16), (-2,14), (-1,10), (-4,7),
  798. (-7,9), (-9,8), (-6,5), (-7,1), (-5,-3), (-8,-6),
  799. (-6,-8), (-4,-5), (0,-7), (4,-5), (6,-8), (8,-6),
  800. (5,-3), (7,1), (6,5), (9,8), (7,9), (4,7), (1,10),
  801. (2,14))),
  802. "circle" : Shape("polygon", ((10,0), (9.51,3.09), (8.09,5.88),
  803. (5.88,8.09), (3.09,9.51), (0,10), (-3.09,9.51),
  804. (-5.88,8.09), (-8.09,5.88), (-9.51,3.09), (-10,0),
  805. (-9.51,-3.09), (-8.09,-5.88), (-5.88,-8.09),
  806. (-3.09,-9.51), (-0.00,-10.00), (3.09,-9.51),
  807. (5.88,-8.09), (8.09,-5.88), (9.51,-3.09))),
  808. "square" : Shape("polygon", ((10,-10), (10,10), (-10,10),
  809. (-10,-10))),
  810. "triangle" : Shape("polygon", ((10,-5.77), (0,11.55),
  811. (-10,-5.77))),
  812. "classic": Shape("polygon", ((0,0),(-5,-9),(0,-7),(5,-9))),
  813. "blank" : Shape("image", self._blankimage())
  814. }
  815. self._bgpics = {"nopic" : ""}
  816. TurtleScreenBase.__init__(self, cv)
  817. self._mode = mode
  818. self._delayvalue = delay
  819. self._colormode = _CFG["colormode"]
  820. self._keys = []
  821. self.clear()
  822. def clear(self):
  823. """Delete all drawings and all turtles from the TurtleScreen.
  824. Reset empty TurtleScreen to its initial state: white background,
  825. no backgroundimage, no eventbindings and tracing on.
  826. No argument.
  827. Example (for a TurtleScreen instance named screen):
  828. screen.clear()
  829. Note: this method is not available as function.
  830. """
  831. self._delayvalue = _CFG["delay"]
  832. self._colormode = _CFG["colormode"]
  833. self._delete("all")
  834. self._bgpic = self._createimage("")
  835. self._bgpicname = "nopic"
  836. self._tracing = 1
  837. self._updatecounter = 0
  838. self._turtles = []
  839. self.bgcolor("white")
  840. for btn in 1, 2, 3:
  841. self.onclick(None, btn)
  842. for key in self._keys[:]:
  843. self.onkey(None, key)
  844. Turtle._pen = None
  845. def mode(self, mode=None):
  846. """Set turtle-mode ('standard', 'logo' or 'world') and perform reset.
  847. Optional argument:
  848. mode -- on of the strings 'standard', 'logo' or 'world'
  849. Mode 'standard' is compatible with turtle.py.
  850. Mode 'logo' is compatible with most Logo-Turtle-Graphics.
  851. Mode 'world' uses userdefined 'worldcoordinates'. *Attention*: in
  852. this mode angles appear distorted if x/y unit-ratio doesn't equal 1.
  853. If mode is not given, return the current mode.
  854. Mode Initial turtle heading positive angles
  855. ------------|-------------------------|-------------------
  856. 'standard' to the right (east) counterclockwise
  857. 'logo' upward (north) clockwise
  858. Examples:
  859. >>> mode('logo') # resets turtle heading to north
  860. >>> mode()
  861. 'logo'
  862. """
  863. if mode is None:
  864. return self._mode
  865. mode = mode.lower()
  866. if mode not in ["standard", "logo", "world"]:
  867. raise TurtleGraphicsError("No turtle-graphics-mode %s" % mode)
  868. self._mode = mode
  869. if mode in ["standard", "logo"]:
  870. self._setscrollregion(-self.canvwidth//2, -self.canvheight//2,
  871. self.canvwidth//2, self.canvheight//2)
  872. self.xscale = self.yscale = 1.0
  873. self.reset()
  874. def setworldcoordinates(self, llx, lly, urx, ury):
  875. """Set up a user defined coordinate-system.
  876. Arguments:
  877. llx -- a number, x-coordinate of lower left corner of canvas
  878. lly -- a number, y-coordinate of lower left corner of canvas
  879. urx -- a number, x-coordinate of upper right corner of canvas
  880. ury -- a number, y-coordinate of upper right corner of canvas
  881. Set up user coodinat-system and switch to mode 'world' if necessary.
  882. This performs a screen.reset. If mode 'world' is already active,
  883. all drawings are redrawn according to the new coordinates.
  884. But ATTENTION: in user-defined coordinatesystems angles may appear
  885. distorted. (see Screen.mode())
  886. Example (for a TurtleScreen instance named screen):
  887. >>> screen.setworldcoordinates(-10,-0.5,50,1.5)
  888. >>> for _ in range(36):
  889. left(10)
  890. forward(0.5)
  891. """
  892. if self.mode() != "world":
  893. self.mode("world")
  894. xspan = float(urx - llx)
  895. yspan = float(ury - lly)
  896. wx, wy = self._window_size()
  897. self.screensize(wx-20, wy-20)
  898. oldxscale, oldyscale = self.xscale, self.yscale
  899. self.xscale = self.canvwidth / xspan
  900. self.yscale = self.canvheight / yspan
  901. srx1 = llx * self.xscale
  902. sry1 = -ury * self.yscale
  903. srx2 = self.canvwidth + srx1
  904. sry2 = self.canvheight + sry1
  905. self._setscrollregion(srx1, sry1, srx2, sry2)
  906. self._rescale(self.xscale/oldxscale, self.yscale/oldyscale)
  907. self.update()
  908. def register_shape(self, name, shape=None):
  909. """Adds a turtle shape to TurtleScreen's shapelist.
  910. Arguments:
  911. (1) name is the name of a gif-file and shape is None.
  912. Installs the corresponding image shape.
  913. !! Image-shapes DO NOT rotate when turning the turtle,
  914. !! so they do not display the heading of the turtle!
  915. (2) name is an arbitrary string and shape is a tuple
  916. of pairs of coordinates. Installs the corresponding
  917. polygon shape
  918. (3) name is an arbitrary string and shape is a
  919. (compound) Shape object. Installs the corresponding
  920. compound shape.
  921. To use a shape, you have to issue the command shape(shapename).
  922. call: register_shape("turtle.gif")
  923. --or: register_shape("tri", ((0,0), (10,10), (-10,10)))
  924. Example (for a TurtleScreen instance named screen):
  925. >>> screen.register_shape("triangle", ((5,-3),(0,5),(-5,-3)))
  926. """
  927. if shape is None:
  928. # image
  929. if name.lower().endswith(".gif"):
  930. shape = Shape("image", self._image(name))
  931. else:
  932. raise TurtleGraphicsError("Bad arguments for register_shape.\n"
  933. + "Use help(register_shape)" )
  934. elif isinstance(shape, tuple):
  935. shape = Shape("polygon", shape)
  936. ## else shape assumed to be Shape-instance
  937. self._shapes[name] = shape
  938. # print "shape added:" , self._shapes
  939. def _colorstr(self, color):
  940. """Return color string corresponding to args.
  941. Argument may be a string or a tuple of three
  942. numbers corresponding to actual colormode,
  943. i.e. in the range 0<=n<=colormode.
  944. If the argument doesn't represent a color,
  945. an error is raised.
  946. """
  947. if len(color) == 1:
  948. color = color[0]
  949. if isinstance(color, str):
  950. if self._iscolorstring(color) or color == "":
  951. return color
  952. else:
  953. raise TurtleGraphicsError("bad color string: %s" % str(color))
  954. try:
  955. r, g, b = color
  956. except:
  957. raise TurtleGraphicsError("bad color arguments: %s" % str(color))
  958. if self._colormode == 1.0:
  959. r, g, b = [round(255.0*x) for x in (r, g, b)]
  960. if not ((0 <= r <= 255) and (0 <= g <= 255) and (0 <= b <= 255)):
  961. raise TurtleGraphicsError("bad color sequence: %s" % str(color))
  962. return "#%02x%02x%02x" % (r, g, b)
  963. def _color(self, cstr):
  964. if not cstr.startswith("#"):
  965. return cstr
  966. if len(cstr) == 7:
  967. cl = [int(cstr[i:i+2], 16) for i in (1, 3, 5)]
  968. elif len(cstr) == 4:
  969. cl = [16*int(cstr[h], 16) for h in cstr[1:]]
  970. else:
  971. raise TurtleGraphicsError("bad colorstring: %s" % cstr)
  972. return tuple([c * self._colormode/255 for c in cl])
  973. def colormode(self, cmode=None):
  974. """Return the colormode or set it to 1.0 or 255.
  975. Optional argument:
  976. cmode -- one of the values 1.0 or 255
  977. r, g, b values of colortriples have to be in range 0..cmode.
  978. Example (for a TurtleScreen instance named screen):
  979. >>> screen.colormode()
  980. 1.0
  981. >>> screen.colormode(255)
  982. >>> turtle.pencolor(240,160,80)
  983. """
  984. if cmode is None:
  985. return self._colormode
  986. if cmode == 1.0:
  987. self._colormode = float(cmode)
  988. elif cmode == 255:
  989. self._colormode = int(cmode)
  990. def reset(self):
  991. """Reset all Turtles on the Screen to their initial state.
  992. No argument.
  993. Example (for a TurtleScreen instance named screen):
  994. >>> screen.reset()
  995. """
  996. for turtle in self._turtles:
  997. turtle._setmode(self._mode)
  998. turtle.reset()
  999. def turtles(self):
  1000. """Return the list of turtles on the screen.
  1001. Example (for a TurtleScreen instance named screen):
  1002. >>> screen.turtles()
  1003. [<turtle.Turtle object at 0x00E11FB0>]
  1004. """
  1005. return self._turtles
  1006. def bgcolor(self, *args):
  1007. """Set or return backgroundcolor of the TurtleScreen.
  1008. Arguments (if given): a color string or three numbers
  1009. in the range 0..colormode or a 3-tuple of such numbers.
  1010. Example (for a TurtleScreen instance named screen):
  1011. >>> screen.bgcolor("orange")
  1012. >>> screen.bgcolor()
  1013. 'orange'
  1014. >>> screen.bgcolor(0.5,0,0.5)
  1015. >>> screen.bgcolor()
  1016. '#800080'
  1017. """
  1018. if args:
  1019. color = self._colorstr(args)
  1020. else:
  1021. color = None
  1022. color = self._bgcolor(color)
  1023. if color is not None:
  1024. color = self._color(color)
  1025. return color
  1026. def tracer(self, n=None, delay=None):
  1027. """Turns turtle animation on/off and set delay for update drawings.
  1028. Optional arguments:
  1029. n -- nonnegative integer
  1030. delay -- nonnegative integer
  1031. If n is given, only each n-th regular screen update is really performed.
  1032. (Can be used to accelerate the drawing of complex graphics.)
  1033. Second arguments sets delay value (see RawTurtle.delay())
  1034. Example (for a TurtleScreen instance named screen):
  1035. >>> screen.tracer(8, 25)
  1036. >>> dist = 2
  1037. >>> for i in range(200):
  1038. fd(dist)
  1039. rt(90)
  1040. dist += 2
  1041. """
  1042. if n is None:
  1043. return self._tracing
  1044. self._tracing = int(n)
  1045. self._updatecounter = 0
  1046. if delay is not None:
  1047. self._delayvalue = int(delay)
  1048. if self._tracing:
  1049. self.update()
  1050. def delay(self, delay=None):
  1051. """ Return or set the drawing delay in milliseconds.
  1052. Optional argument:
  1053. delay -- positive integer
  1054. Example (for a TurtleScreen instance named screen):
  1055. >>> screen.delay(15)
  1056. >>> screen.delay()
  1057. 15
  1058. """
  1059. if delay is None:
  1060. return self._delayvalue
  1061. self._delayvalue = int(delay)
  1062. def _incrementudc(self):
  1063. "Increment upadate counter."""
  1064. if not TurtleScreen._RUNNING:
  1065. TurtleScreen._RUNNNING = True
  1066. raise Terminator
  1067. if self._tracing > 0:
  1068. self._updatecounter += 1
  1069. self._updatecounter %= self._tracing
  1070. def update(self):
  1071. """Perform a TurtleScreen update.
  1072. """
  1073. tracing = self._tracing
  1074. self._tracing = True
  1075. for t in self.turtles():
  1076. t._update_data()
  1077. t._drawturtle()
  1078. self._tracing = tracing
  1079. self._update()
  1080. def window_width(self):
  1081. """ Return the width of the turtle window.
  1082. Example (for a TurtleScreen instance named screen):
  1083. >>> screen.window_width()
  1084. 640
  1085. """
  1086. return self._window_size()[0]
  1087. def window_height(self):
  1088. """ Return the height of the turtle window.
  1089. Example (for a TurtleScreen instance named screen):
  1090. >>> screen.window_height()
  1091. 480
  1092. """
  1093. return self._window_size()[1]
  1094. def getcanvas(self):
  1095. """Return the Canvas of this TurtleScreen.
  1096. No argument.
  1097. Example (for a Screen instance named screen):
  1098. >>> cv = screen.getcanvas()
  1099. >>> cv
  1100. <turtle.ScrolledCanvas instance at 0x010742D8>
  1101. """
  1102. return self.cv
  1103. def getshapes(self):
  1104. """Return a list of names of all currently available turtle shapes.
  1105. No argument.
  1106. Example (for a TurtleScreen instance named screen):
  1107. >>> screen.getshapes()
  1108. ['arrow', 'blank', 'circle', ... , 'turtle']
  1109. """
  1110. return sorted(self._shapes.keys())
  1111. def onclick(self, fun, btn=1, add=None):
  1112. """Bind fun to mouse-click event on canvas.
  1113. Arguments:
  1114. fun -- a function with two arguments, the coordinates of the
  1115. clicked point on the canvas.
  1116. num -- the number of the mouse-button, defaults to 1
  1117. Example (for a TurtleScreen instance named screen
  1118. and a Turtle instance named turtle):
  1119. >>> screen.onclick(turtle.goto)
  1120. ### Subsequently clicking into the TurtleScreen will
  1121. ### make the turtle move to the clicked point.
  1122. >>> screen.onclick(None)
  1123. ### event-binding will be removed
  1124. """
  1125. self._onscreenclick(fun, btn, add)
  1126. def onkey(self, fun, key):
  1127. """Bind fun to key-release event of key.
  1128. Arguments:
  1129. fun -- a function with no arguments
  1130. key -- a string: key (e.g. "a") or key-symbol (e.g. "space")
  1131. In order to be able to register key-events, TurtleScreen
  1132. must have focus. (See method listen.)
  1133. Example (for a TurtleScreen instance named screen
  1134. and a Turtle instance named turtle):
  1135. >>> def f():
  1136. fd(50)
  1137. lt(60)
  1138. >>> screen.onkey(f, "Up")
  1139. >>> screen.listen()
  1140. ### Subsequently the turtle can be moved by
  1141. ### repeatedly pressing the up-arrow key,
  1142. ### consequently drawing a hexagon
  1143. """
  1144. if fun is None:
  1145. if key in self._keys:
  1146. self._keys.remove(key)
  1147. elif key not in self._keys:
  1148. self._keys.append(key)
  1149. self._onkey(fun, key)
  1150. def listen(self, xdummy=None, ydummy=None):
  1151. """Set focus on TurtleScreen (in order to collect key-events)
  1152. No arguments.
  1153. Dummy arguments are provided in order
  1154. to be able to pass listen to the onclick method.
  1155. Example (for a TurtleScreen instance named screen):
  1156. >>> screen.listen()
  1157. """
  1158. self._listen()
  1159. def ontimer(self, fun, t=0):
  1160. """Install a timer, which calls fun after t milliseconds.
  1161. Arguments:
  1162. fun -- a function with no arguments.
  1163. t -- a number >= 0
  1164. Example (for a TurtleScreen instance named screen):
  1165. >>> running = True
  1166. >>> def f():
  1167. if running:
  1168. fd(50)
  1169. lt(60)
  1170. screen.ontimer(f, 250)
  1171. >>> f() ### makes the tu

Large files files are truncated, but you can click here to view the full file