gh-126349: Add 'fill', 'poly', and 'no_animation' context managers to turtle (#126350)

Co-authored-by: Marie Roald <roald.marie@gmail.com>
Co-authored-by: Yngve Mardal Moe <yngve.m.moe@gmail.com>
Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
Co-authored-by: Daniel Hollas <danekhollas@gmail.com>
Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
Co-authored-by: Erlend E. Aasland <erlend@python.org>
This commit is contained in:
Marie Roald 2025-01-18 11:27:22 +01:00 committed by GitHub
parent 4dade055f4
commit d3adf02c90
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 277 additions and 16 deletions

View file

@ -107,6 +107,7 @@ import sys
from os.path import isfile, split, join
from pathlib import Path
from contextlib import contextmanager
from copy import deepcopy
from tkinter import simpledialog
@ -114,23 +115,24 @@ _tg_classes = ['ScrolledCanvas', 'TurtleScreen', 'Screen',
'RawTurtle', 'Turtle', 'RawPen', 'Pen', 'Shape', 'Vec2D']
_tg_screen_functions = ['addshape', 'bgcolor', 'bgpic', 'bye',
'clearscreen', 'colormode', 'delay', 'exitonclick', 'getcanvas',
'getshapes', 'listen', 'mainloop', 'mode', 'numinput',
'getshapes', 'listen', 'mainloop', 'mode', 'no_animation', 'numinput',
'onkey', 'onkeypress', 'onkeyrelease', 'onscreenclick', 'ontimer',
'register_shape', 'resetscreen', 'screensize', 'save', 'setup',
'setworldcoordinates', 'textinput', 'title', 'tracer', 'turtles', 'update',
'window_height', 'window_width']
'setworldcoordinates', 'textinput', 'title', 'tracer', 'turtles',
'update', 'window_height', 'window_width']
_tg_turtle_functions = ['back', 'backward', 'begin_fill', 'begin_poly', 'bk',
'circle', 'clear', 'clearstamp', 'clearstamps', 'clone', 'color',
'degrees', 'distance', 'dot', 'down', 'end_fill', 'end_poly', 'fd',
'fillcolor', 'filling', 'forward', 'get_poly', 'getpen', 'getscreen', 'get_shapepoly',
'getturtle', 'goto', 'heading', 'hideturtle', 'home', 'ht', 'isdown',
'isvisible', 'left', 'lt', 'onclick', 'ondrag', 'onrelease', 'pd',
'pen', 'pencolor', 'pendown', 'pensize', 'penup', 'pos', 'position',
'pu', 'radians', 'right', 'reset', 'resizemode', 'rt',
'seth', 'setheading', 'setpos', 'setposition',
'setundobuffer', 'setx', 'sety', 'shape', 'shapesize', 'shapetransform', 'shearfactor', 'showturtle',
'speed', 'st', 'stamp', 'teleport', 'tilt', 'tiltangle', 'towards',
'turtlesize', 'undo', 'undobufferentries', 'up', 'width',
'fillcolor', 'fill', 'filling', 'forward', 'get_poly', 'getpen',
'getscreen', 'get_shapepoly', 'getturtle', 'goto', 'heading',
'hideturtle', 'home', 'ht', 'isdown', 'isvisible', 'left', 'lt',
'onclick', 'ondrag', 'onrelease', 'pd', 'pen', 'pencolor', 'pendown',
'pensize', 'penup', 'poly', 'pos', 'position', 'pu', 'radians', 'right',
'reset', 'resizemode', 'rt', 'seth', 'setheading', 'setpos',
'setposition', 'setundobuffer', 'setx', 'sety', 'shape', 'shapesize',
'shapetransform', 'shearfactor', 'showturtle', 'speed', 'st', 'stamp',
'teleport', 'tilt', 'tiltangle', 'towards', 'turtlesize', 'undo',
'undobufferentries', 'up', 'width',
'write', 'xcor', 'ycor']
_tg_utilities = ['write_docstringdict', 'done']
@ -1275,6 +1277,26 @@ class TurtleScreen(TurtleScreenBase):
return self._delayvalue
self._delayvalue = int(delay)
@contextmanager
def no_animation(self):
"""Temporarily turn off auto-updating the screen.
This is useful for drawing complex shapes where even the fastest setting
is too slow. Once this context manager is exited, the drawing will
be displayed.
Example (for a TurtleScreen instance named screen
and a Turtle instance named turtle):
>>> with screen.no_animation():
... turtle.circle(50)
"""
tracer = self.tracer()
try:
self.tracer(0)
yield
finally:
self.tracer(tracer)
def _incrementudc(self):
"""Increment update counter."""
if not TurtleScreen._RUNNING:
@ -3380,6 +3402,24 @@ class RawTurtle(TPen, TNavigator):
"""
return isinstance(self._fillpath, list)
@contextmanager
def fill(self):
"""A context manager for filling a shape.
Implicitly ensures the code block is wrapped with
begin_fill() and end_fill().
Example (for a Turtle instance named turtle):
>>> turtle.color("black", "red")
>>> with turtle.fill():
... turtle.circle(60)
"""
self.begin_fill()
try:
yield
finally:
self.end_fill()
def begin_fill(self):
"""Called just before drawing a shape to be filled.
@ -3400,7 +3440,6 @@ class RawTurtle(TPen, TNavigator):
self.undobuffer.push(("beginfill", self._fillitem))
self._update()
def end_fill(self):
"""Fill the shape drawn after the call begin_fill().
@ -3504,6 +3543,27 @@ class RawTurtle(TPen, TNavigator):
if self.undobuffer:
self.undobuffer.cumulate = False
@contextmanager
def poly(self):
"""A context manager for recording the vertices of a polygon.
Implicitly ensures that the code block is wrapped with
begin_poly() and end_poly()
Example (for a Turtle instance named turtle) where we create a
triangle as the polygon and move the turtle 100 steps forward:
>>> with turtle.poly():
... for side in range(3)
... turtle.forward(50)
... turtle.right(60)
>>> turtle.forward(100)
"""
self.begin_poly()
try:
yield
finally:
self.end_poly()
def begin_poly(self):
"""Start recording the vertices of a polygon.