Python龟色变化
Python Turtle color change
我目前正在玩 pythons turtle 模块,我正在尝试制作一个不透明方形网格,比如 30x30,它可以根据一些 属性 改变颜色(无关紧要 属性 ) 我的问题是,一旦形状已经绘制在 canvas 上,是否仍然可以更改形状的颜色?
我试过将所有正方形添加到一个数组中,包括图章和多边形,但似乎无法在绘制后更改其中任何一个的颜色。
我知道图章不起作用,因为它就像海龟所在位置的足迹,但是否有任何方法允许使用多边形或其他我不知道的方法?
我没有添加任何代码片段,因为这是一个非常基本的问题,可以用于很多事情。
Turtle 的想法是,图像一旦绘制,就会变成像素,提交给 canvas - 即使 Turtle 命令本身是 "vector" 命令,当人们谈论 "vectorial" 对比 "raster" 图形。
这意味着 Turtle 绘图上下文无法知道已绘制的内容 "by itself" - 您无法引用已绘制的形状或多边形并更改其属性。 (更新:但对于邮票 - Turtle 对象确实记录了有关这些的信息 - 感谢@cdlane)
在这种情况下,您需要做的是在 您的 代码数据上注释您想要进一步修改的任何形状 - 然后将它们重新绘制不知何故,当你需要它。换句话说:您为矢量图形模型开发代码 - 它允许您这样做。
但是,您应该注意,tkinter Canvas widget,Turtle 在其上运行(至少,我相信),它本身就是一个 Vector 模型 - 因此它可能更适合您所拥有的心里。不过,它的文档和工作方式可能很难掌握。
因此,回到 "having your own Vector graphics implementation",您可以利用 Python 面向对象和数据模型来构建 "history-turtle" - 它可以记录日志并在其中重播命令块相同的位置上下文(但允许不同的颜色、宽度等...设置)。
做起来比说起来难,但是下面是一个示例:
from turtle import Turtle
"""
Python Turtle with logging and replay capabilities
Author: João S. O. Bueno <gwidion@gmail.com>
License: LGPL 3.0+
This implements HistoryTurtle - a subclass of
Python's turtle.Turtle wich features a simple
command history and new `replay` and `log`
methods -
`turtle.replay(<start>, <end>)` will reissue
the commands logged in those positions of the history,
but with the current Pen settings.
The optional kwarg `position_independent` can be passed
as `True` to `replay` so that the turtle's position
and heading are not restored to the ones recorded
along with the command.
https://gist.github.com/jsbueno/cb413e985747392c460f39cc138436bc
"""
class Command:
__slots__ = ( "method_name", "args", "kwargs", "pos", "heading")
def __init__(self, method_name, args=(),
kwargs=None, pos=None, heading=None):
self.method_name = method_name
self.args = args
self.kwargs = kwargs or {}
self.pos = pos
self.heading = heading
def __repr__(self):
return "<{0}> - {1}".format(self.pos, self.method_name)
class Instrumented:
def __init__(self, turtle, method):
self.turtle = turtle
self.method = method
def __call__(self, *args, **kwargs):
command = Command(self.method.__name__, args, kwargs,
self.pos(), self.heading())
result = self.method(*args, **kwargs)
if (self.method.__name__ not in self.turtle.methods_to_skip or
not kwargs.pop('skip_self', True)):
self.turtle.history.append(command)
return result
def pos(self):
return self.turtle._execute(Command('pos'), True)
def heading(self):
return self.turtle._execute(Command('heading'), True)
class HistoryTurtle(Turtle):
methods_to_skip = ('replay', '_execute', 'log')
def __init__(self, *args, **kw):
self._inited = False
super().__init__(*args, **kw)
self.history = []
self._replaying = [False]
self._inited = True
def __getattribute__(self, attr):
result = super().__getattribute__(attr)
if (not callable(result) or
attr.startswith('_') or
not self._inited or
self._replaying[-1]):
return result
return Instrumented(self, result)
def replay(self, start, end=None, *,
position_independent=False,
skip_self=True,
restore=True
):
results = []
self._replaying.append(True)
if restore:
pos, heading, state = self.pos(), self.heading(), self.pen()['pendown']
for command in self.history[start:end]:
results.append(
self._execute(command, position_independent))
if restore:
self.setpos(pos)
self.setheading(heading)
(self.pendown() if state else self.penup())
self._replaying.pop()
return results
def log(self, start=0, end=None):
for i, command in enumerate(self.history[start:end], start):
print(i, command)
def _execute(self, command, position_independent):
""" Execute a method without triggering the log
"""
# Warning: not thread-safe:
self._replaying.append(True)
method = getattr(self, command.method_name)
if not position_independent:
state = self.pen()['pendown']
self.setpos(command.pos)
self.setheading(command.heading)
(self.pendown() if state else self.penup())
result = method(*command.args, **command.kwargs)
self._replaying.pop()
return result
是的,你可以做到。这个问题的关键,以及许多复杂的乌龟问题,都是使用图章。它们可以单独或一起移动。由于它们采用乌龟本身的形状,因此它们可以是图像或任意大小或颜色的任意多边形:
from turtle import Turtle, Screen
from random import randrange, choice
from collections import namedtuple
from math import ceil
GRID = 15 # GRID by GRID of squares
SIZE = 30 # each square is SIZE by SIZE
INCREASE = 1.5 # how much to lighten the square's color
WHITE = [255, 255, 255] # color at which we stop changing square
DELAY = 100 # time between calls to change() in milliseconds
DARK = 32 # range (ceil(INCREASE) .. DARK - 1) of dark colors
def change():
block = choice(blocks)
blocks.remove(block)
color = [min(int(primary * INCREASE), WHITE[i]) for i, primary in enumerate(block.color)] # lighten color
turtle.color(color)
turtle.setposition(block.position)
turtle.clearstamp(block.stamp)
stamp = turtle.stamp()
if color != WHITE:
blocks.append(Block(block.position, color, stamp)) # not white yet so keep changing this block
if blocks: # stop all changes if/when all blocks turn white
screen.ontimer(change, DELAY)
HALF_SIZE = SIZE // 2
screen = Screen()
screen.colormode(WHITE[0])
screen.register_shape("block", ((HALF_SIZE, -HALF_SIZE), (HALF_SIZE, HALF_SIZE), (-HALF_SIZE, HALF_SIZE), (-HALF_SIZE, -HALF_SIZE)))
screen.tracer(GRID ** 2) # ala @PyNuts
turtle = Turtle(shape="block", visible=False)
turtle.speed("fastest")
turtle.up()
Block = namedtuple('Block', ['position', 'color', 'stamp'])
blocks = list()
HALF_GRID = GRID // 2
for x in range(-HALF_GRID, HALF_GRID):
for y in range(-HALF_GRID, HALF_GRID):
turtle.goto(x * SIZE, y * SIZE)
color = [randrange(ceil(INCREASE), DARK) for primary in WHITE]
turtle.color(color)
blocks.append(Block(turtle.position(), color, turtle.stamp()))
screen.ontimer(change, DELAY)
screen.exitonclick()
我目前正在玩 pythons turtle 模块,我正在尝试制作一个不透明方形网格,比如 30x30,它可以根据一些 属性 改变颜色(无关紧要 属性 ) 我的问题是,一旦形状已经绘制在 canvas 上,是否仍然可以更改形状的颜色?
我试过将所有正方形添加到一个数组中,包括图章和多边形,但似乎无法在绘制后更改其中任何一个的颜色。
我知道图章不起作用,因为它就像海龟所在位置的足迹,但是否有任何方法允许使用多边形或其他我不知道的方法?
我没有添加任何代码片段,因为这是一个非常基本的问题,可以用于很多事情。
Turtle 的想法是,图像一旦绘制,就会变成像素,提交给 canvas - 即使 Turtle 命令本身是 "vector" 命令,当人们谈论 "vectorial" 对比 "raster" 图形。
这意味着 Turtle 绘图上下文无法知道已绘制的内容 "by itself" - 您无法引用已绘制的形状或多边形并更改其属性。 (更新:但对于邮票 - Turtle 对象确实记录了有关这些的信息 - 感谢@cdlane)
在这种情况下,您需要做的是在 您的 代码数据上注释您想要进一步修改的任何形状 - 然后将它们重新绘制不知何故,当你需要它。换句话说:您为矢量图形模型开发代码 - 它允许您这样做。
但是,您应该注意,tkinter Canvas widget,Turtle 在其上运行(至少,我相信),它本身就是一个 Vector 模型 - 因此它可能更适合您所拥有的心里。不过,它的文档和工作方式可能很难掌握。
因此,回到 "having your own Vector graphics implementation",您可以利用 Python 面向对象和数据模型来构建 "history-turtle" - 它可以记录日志并在其中重播命令块相同的位置上下文(但允许不同的颜色、宽度等...设置)。
做起来比说起来难,但是下面是一个示例:
from turtle import Turtle
"""
Python Turtle with logging and replay capabilities
Author: João S. O. Bueno <gwidion@gmail.com>
License: LGPL 3.0+
This implements HistoryTurtle - a subclass of
Python's turtle.Turtle wich features a simple
command history and new `replay` and `log`
methods -
`turtle.replay(<start>, <end>)` will reissue
the commands logged in those positions of the history,
but with the current Pen settings.
The optional kwarg `position_independent` can be passed
as `True` to `replay` so that the turtle's position
and heading are not restored to the ones recorded
along with the command.
https://gist.github.com/jsbueno/cb413e985747392c460f39cc138436bc
"""
class Command:
__slots__ = ( "method_name", "args", "kwargs", "pos", "heading")
def __init__(self, method_name, args=(),
kwargs=None, pos=None, heading=None):
self.method_name = method_name
self.args = args
self.kwargs = kwargs or {}
self.pos = pos
self.heading = heading
def __repr__(self):
return "<{0}> - {1}".format(self.pos, self.method_name)
class Instrumented:
def __init__(self, turtle, method):
self.turtle = turtle
self.method = method
def __call__(self, *args, **kwargs):
command = Command(self.method.__name__, args, kwargs,
self.pos(), self.heading())
result = self.method(*args, **kwargs)
if (self.method.__name__ not in self.turtle.methods_to_skip or
not kwargs.pop('skip_self', True)):
self.turtle.history.append(command)
return result
def pos(self):
return self.turtle._execute(Command('pos'), True)
def heading(self):
return self.turtle._execute(Command('heading'), True)
class HistoryTurtle(Turtle):
methods_to_skip = ('replay', '_execute', 'log')
def __init__(self, *args, **kw):
self._inited = False
super().__init__(*args, **kw)
self.history = []
self._replaying = [False]
self._inited = True
def __getattribute__(self, attr):
result = super().__getattribute__(attr)
if (not callable(result) or
attr.startswith('_') or
not self._inited or
self._replaying[-1]):
return result
return Instrumented(self, result)
def replay(self, start, end=None, *,
position_independent=False,
skip_self=True,
restore=True
):
results = []
self._replaying.append(True)
if restore:
pos, heading, state = self.pos(), self.heading(), self.pen()['pendown']
for command in self.history[start:end]:
results.append(
self._execute(command, position_independent))
if restore:
self.setpos(pos)
self.setheading(heading)
(self.pendown() if state else self.penup())
self._replaying.pop()
return results
def log(self, start=0, end=None):
for i, command in enumerate(self.history[start:end], start):
print(i, command)
def _execute(self, command, position_independent):
""" Execute a method without triggering the log
"""
# Warning: not thread-safe:
self._replaying.append(True)
method = getattr(self, command.method_name)
if not position_independent:
state = self.pen()['pendown']
self.setpos(command.pos)
self.setheading(command.heading)
(self.pendown() if state else self.penup())
result = method(*command.args, **command.kwargs)
self._replaying.pop()
return result
是的,你可以做到。这个问题的关键,以及许多复杂的乌龟问题,都是使用图章。它们可以单独或一起移动。由于它们采用乌龟本身的形状,因此它们可以是图像或任意大小或颜色的任意多边形:
from turtle import Turtle, Screen
from random import randrange, choice
from collections import namedtuple
from math import ceil
GRID = 15 # GRID by GRID of squares
SIZE = 30 # each square is SIZE by SIZE
INCREASE = 1.5 # how much to lighten the square's color
WHITE = [255, 255, 255] # color at which we stop changing square
DELAY = 100 # time between calls to change() in milliseconds
DARK = 32 # range (ceil(INCREASE) .. DARK - 1) of dark colors
def change():
block = choice(blocks)
blocks.remove(block)
color = [min(int(primary * INCREASE), WHITE[i]) for i, primary in enumerate(block.color)] # lighten color
turtle.color(color)
turtle.setposition(block.position)
turtle.clearstamp(block.stamp)
stamp = turtle.stamp()
if color != WHITE:
blocks.append(Block(block.position, color, stamp)) # not white yet so keep changing this block
if blocks: # stop all changes if/when all blocks turn white
screen.ontimer(change, DELAY)
HALF_SIZE = SIZE // 2
screen = Screen()
screen.colormode(WHITE[0])
screen.register_shape("block", ((HALF_SIZE, -HALF_SIZE), (HALF_SIZE, HALF_SIZE), (-HALF_SIZE, HALF_SIZE), (-HALF_SIZE, -HALF_SIZE)))
screen.tracer(GRID ** 2) # ala @PyNuts
turtle = Turtle(shape="block", visible=False)
turtle.speed("fastest")
turtle.up()
Block = namedtuple('Block', ['position', 'color', 'stamp'])
blocks = list()
HALF_GRID = GRID // 2
for x in range(-HALF_GRID, HALF_GRID):
for y in range(-HALF_GRID, HALF_GRID):
turtle.goto(x * SIZE, y * SIZE)
color = [randrange(ceil(INCREASE), DARK) for primary in WHITE]
turtle.color(color)
blocks.append(Block(turtle.position(), color, turtle.stamp()))
screen.ontimer(change, DELAY)
screen.exitonclick()