python冲击二级—基本库turtle,海龟绘图详解,史上最全,没有之一

** turtle — 海龟绘图**

海龟绘图很适合用来引导孩子学习编程。最初来自于 Wally Feurzeig, Seymour Papert 和 Cynthia Solomon 于1967 年所创造的 Logo 编程语言。请想象绘图区有一只机器海龟,起始位置在 x-y 平面的 (0, 0) 点。

首先了解下海龟绘图的坐标体系:
图中红点部分,就是海龟画笔的起点坐标(0,0),海龟的头部是x轴方向,为0度。看看这个坐标系的代码:

import turtle
#写下坐标
turtle.write(turtle.position(),align="right")
#画一个直径为10的红色圆点
turtle.dot(10,'red')
#前进200个像素距离
turtle.forward(200)
#盖上印章,默认为海龟的形状
turtle.stamp()
#写上x,代表x轴
turtle.write("x")
#写上坐标
turtle.write(turtle.position(),align="right")
#返回原点
turtle.home()
#海龟方向左转90度,也就是逆时针
turtle.left(90)
#前进200
turtle.forward(200)
turtle.stamp()
turtle.write("y")
turtle.write(turtle.position(),align="right")

turtle.home()
turtle.left(180)

turtle.forward(200)
turtle.write(turtle.position(),align="right")

turtle.home()
turtle.left(270)

turtle.forward(200)
turtle.write(turtle.position(),align="right")

turtle.home()
#为了保留图形,开启循环
turtle.done()

了解了坐标系,我们就能按照要求画出合适的图形,上面的事全部的流程,我们可以用循环简化代码。

import turtle
#写下坐标
turtle.write(turtle.position(),align="right")
#画一个直径为10的红色圆点
turtle.dot(10,'red')
#前进200个像素距离
agel = 0
for i in ("xy"):
    turtle.left(agel)
    turtle.forward(200)
    turtle.stamp()
    turtle.write(i)
    turtle.write(turtle.position(),align="right")
    #后退400
    turtle.backward(400)
    turtle.home()
    #角度增加
    agel += 90 
turtle.done()

下面我们了解一下turtle的各个画图工具函数:

海龟动作

移动和绘制

forward() | fd() 前进
backward() | bk() | back() 后退
right() | rt() 右转
left() | lt() 左转
goto() | setpos() | setposition() 前往/定位
setx() 设置 x 坐标
sety() 设置 y 坐标
setheading() | seth() 设置朝向
home() 返回原点
circle() 画圆
dot() 画点
stamp() 印章
clearstamp() 清除印章
clearstamps() 清除多个印章
undo() 撤消
speed() 速度

获取海龟的状态
position() | pos() 位置
towards() 目标方向
xcor() x 坐标
ycor() y 坐标
heading() 朝向
distance() 距离

设置与度量单位

degrees() 角度
radians() 弧度

画笔控制

绘图状态

pendown() | pd() | down() 画笔落下
penup() | pu() | up() 画笔抬起
pensize() | width() 画笔粗细
pen() 画笔
isdown() 画笔是否落下

颜色控制
color() 颜色
pencolor() 画笔颜色
fillcolor() 填充颜色

填充
filling() 是否填充
begin_fill() 开始填充
end_fill() 结束填充

更多绘图控制
reset() 重置
clear() 清空
write() 书写

海龟状态

可见性
showturtle() | st() 显示海龟
hideturtle() | ht() 隐藏海龟
isvisible() 是否可见

外观
shape() 形状
resizemode() 大小调整模式
shapesize() | turtlesize() 形状大小
shearfactor() 剪切因子
settiltangle() 设置倾角
tiltangle() 倾角
tilt() 倾斜
shapetransform() 变形
get_shapepoly() 获取形状多边形

使用事件
onclick() 当鼠标点击
onrelease() 当鼠标释放
ondrag() 当鼠标拖动

特殊海龟方法
begin_poly() 开始记录多边形
end_poly() 结束记录多边形
get_poly() 获取多边形
clone() 克隆
getturtle() | getpen() 获取海龟画笔
getscreen() 获取屏幕
setundobuffer() 设置撤消缓冲区
undobufferentries() 撤消缓冲区条目数

TurtleScreen/Screen 方法

窗口控制
bgcolor() 背景颜色
bgpic() 背景图片
clearscreen()
resetscreen()
screensize() 屏幕大小
setworldcoordinates() 设置世界坐标系

动画控制
delay() 延迟
tracer() 追踪
update() 更新

使用屏幕事件
listen() 监听
onkey() | onkeyrelease() 当键盘按下并释放
onkeypress() 当键盘按下
onclick() | onscreenclick() 当点击屏幕
ontimer() 当达到定时
mainloop() | done() 主循环

设置与特殊方法
mode()
colormode() 颜色模式
getcanvas() 获取画布
getshapes() 获取形状
register_shape() | addshape() 添加形状
turtles() 所有海龟
window_height() 窗口高度
window_width() 窗口宽度

输入方法
textinput() 文本输入
numinput() 数字输入

Screen 专有方法
bye() 退出
exitonclick() 当点击时退出
setup() 设置
title() 标题

下面我们通过示例来了解绘图的各个方法:

为了方便学习,先画出一个虚线的坐标系,x,y方向都是±400,作为我们底图,通过坐标来研究各个函数的绘图结果

import turtle

def coord():
    angle = 0
    for i in [(-400,0),(0,-400)]:
        turtle.penup()
        turtle.goto(*i)
        turtle.left(angle)
        for _ in range(40):
        #通过画笔抬起再放下画出虚线
            turtle.pendown()
            turtle.forward(10)
            turtle.penup()
            turtle.forward(10)
        angle += 90
    turtle.home()
    turtle.pendown()

首先请大家记住,在我们画图过程中,如果没有明确的指定坐标,角度,那我们所有的角度,位置都是相对的,相对当前海龟的位置和角度。

turtle.circle(radius, extent=None, steps=None)
参数
• radius -- 一个数值
• extent -- 一个数值 (或 None)
• steps -- 一个整型数 (或 None)
绘制一个 radius 指定半径的圆。圆心在海龟左边 radius 个单位;extent 为一个夹角,用来决定绘制
圆的一部分。如未指定 extent* 则绘制整个圆。如果 *extent 不是完整圆周,则以当前画笔位置为一
个端点绘制圆弧。如果 radius 为正值则朝逆时针方向绘制圆弧,否则朝顺时针方向。最终海龟的朝
向会依据 extent 的值而改变。
圆实际是以其内切正多边形来近似表示的,其边的数量由 steps 指定。如果未指定边数则会自动确
定。此方法也可用来绘制正多边形。
import turtle

#设置画图速度
turtle.speed('fast')
#设置窗口标题
turtle.title("海龟绘图学习")
#设置画笔粗细
turtle.pensize(3)
#绘制虚线坐标系
def coord():
    angle = 0
    for i in [(-400,0),(0,-400)]:
        turtle.penup()
        turtle.goto(*i)
        turtle.left(angle)
        for _ in range(40):
            turtle.pendown()
            turtle.forward(10)
            turtle.penup()
            turtle.forward(10)
        angle += 90
    turtle.home()
    turtle.pendown()

coord()

#画一个半径为100的圆形,注意圆心位置

turtle.circle(100)
turtle.goto(0,100)
turtle.dot(10,'red')
turtle.write("这是圆心位置{}".format(turtle.pos()))
turtle.done()

下面是通过circle函数化半圆只需更改部分参数即可,和多边形的示例:

#第二个参数改为180度画半圆,也可为复数,则顺时针画圆
turtle.circle(100,180)
#画六边形
turtle.circle(100,360,6)
#画三角形
turtle.circle(100,360,3)

turtle.goto(x, y=None)
turtle.setpos(x, y=None)
turtle.setposition(x, y=None)
参数
• x -- 一个数值或数值对/向量
• y -- 一个数值或 None
如果 y 为 None,x 应为一个表示坐标的数值对或Vec2D 类对象 (例如pos() 返回的对象).
海龟移动到一个绝对坐标。如果画笔已落下将会画线。不改变海龟的朝向。
turtle.speed(speed=None)
参数 speed -- 一个 0..10 范围内的整型数或速度字符串 (见下)
设置海龟移动的速度为 0..10 表示的整型数值。如未指定参数则返回当前速度。
如果输入数值大于 10 或小于 0.5 则速度设为 0。速度字符串与速度值的对应关系如下:
• ”fastest”: 0 最快
• ”fast”: 10 快
• ”normal”: 6 正常
• ”slow”: 3 慢
• ”slowest”: 1 最慢
速度值从 1 到 10,画线和海龟转向的动画效果逐级加快。
注意: speed = 0 表示 没有动画效果。forward/back 将使海龟向前/向后跳跃,同样的 left/right 将使海
龟立即改变朝向。

如果我们要画一个直角三角形怎么办,一个正方形怎么办,显然circle函数无法满足我们的所有要求,那就要利用角度和移动来绘画:

turtle.left(angle)
turtle.lt(angle)
参数 angle -- 一个数值 (整型或浮点型)
海龟左转 angle 个单位。(单位默认为角度,但可通过degrees() 和radians() 函数改变设置。)
角度的正负由海龟模式确定,参见mode()。
turtle.right(angle)
turtle.rt(angle)
参数 angle -- 一个数值 (整型或浮点型)
海龟右转 angle 个单位。(单位默认为角度,但可通过degrees() 和radians() 函数改变设置。)
角度的正负由海龟模式确定,参见mode()。
turtle.setheading(to_angle)
turtle.seth(to_angle)
参数 to_angle -- 一个数值 (整型或浮点型)
设置海龟的朝向为 to_angle。以下是以角度表示的几个常用方向:

标准模式      logo 模式
  0 - 东        0 - 北
 90 - 北       90 - 东
180 - 西      180 - 南
270 - 南      270 - 西

以上为三个调整海龟角度朝向的函数,我们大部分的图形都是要靠它们来完成的。


turtle.color("red")

#平行四边形,夹角分别为60度,120度
#提起画笔
turtle.penup()
#设置海龟坐标(150,150)
turtle.setpos(150,150)
#放下画笔开始绘画
turtle.pendown()
#利用setheading,改变方向,
turtle.fd(100)
#角度为为对比x轴方向的偏移度数
turtle.setheading(60)
turtle.fd(50)
turtle.setheading(180)
turtle.fd(100)
turtle.setheading(240)
turtle.fd(50)
turtle.done()

利用turtle.left画平行四边形

turtle.color("red")

#平行四边形,夹角分别为60度,120度
#提起画笔
turtle.penup()
#设置海龟坐标(150,150)
turtle.setpos(150,150)
#放下画笔开始绘画
turtle.pendown()
turtle.fd(100)
#left,和right为相对当前海龟方向的角度,这一天和setheading不同,注意区分
turtle.left(60)
turtle.fd(50)
turtle.left(120)
turtle.fd(100)
turtle.left(60)
turtle.fd(50)
turtle.done()


大家要仔细体会setheading和left或者right的不同,这对以后做图很重要,setheading,是不管当前的偏移量,每次计算都以初始的角度计算也就是平行于x轴方向,而left和right是相对的角度,相对于当前的海龟方向。

turtle.dot(size=None, *color)
参数
• size -- 一个整型数 >= 1 (如果指定)
• color -- 一个颜色字符串或颜色数值元组
绘制一个直径为 size,颜色为 color 的圆点。如果 size 未指定,则直径取 pensize+4 和 2*pensize 中的
较大值。

turtle.stamp()
在 海 龟 当 前 位 置 印 制 一 个 海 龟 形 状。 返 回 该 印 章 的 stamp_id, 印 章 可 以 通 过 调 用
clearstamp(stamp_id) 来删除。

turtle.clearstamp(stampid)
参数 stampid -- 一个整型数,必须是之前stamp() 调用的返回值

turtle.clearstamps(n=None)
参数 n -- 一个整型数 (或 None)
删除全部或前/后 n 个海龟印章。如果 n 为 None 则删除全部印章,如果 n > 0 则删除前 n 个印章,
否则如果 n < 0 则删除后 n 个印章。

turtle.undo()
撤消 (或连续撤消) 最近的一个 (或多个) 海龟动作。可撤消的次数由撤消缓冲区的大小决定。

turtle.speed(speed=None)
参数 speed -- 一个 0..10 范围内的整型数或速度字符串 (见下)
设置海龟移动的速度为 0..10 表示的整型数值。如未指定参数则返回当前速度。
如果输入数值大于 10 或小于 0.5 则速度设为 0。速度字符串与速度值的对应关系如下:
• ”fastest”: 0 最快
• ”fast”: 10 快
• ”normal”: 6 正常
• ”slow”: 3 慢
• ”slowest”: 1 最慢
速度值从 1 到 10,画线和海龟转向的动画效果逐级加快。
注意: speed = 0 表示 没有动画效果。forward/back 将使海龟向前/向后跳跃,同样的 left/right 将使海
龟立即改变朝向。

下面我们利用点来画一个正弦曲线

turtle.color("red")
import math
for i in range(0,360,5):
    turtle.penup()
    #避免结果过小y值加了两个常数
    turtle.goto(i,math.sin(i*10)*20)
    turtle.pendown()
    turtle.dot(10)
   
turtle.done()

好丑啊,哈哈哈,数学早就忘了,希望你画出来的比我好看,笔者实在是没有艺术细胞!!
关于移动和绘制方面的函数基本也就这么多了,大家组合好了,就可以画出不同的图形,多写多练,关键还要有构图的思维,下面我们来熟悉其他的函数。

turtle.pendown()
turtle.pd()
turtle.down()
画笔落下 -- 移动时将画线。

turtle.penup()
turtle.pu()
turtle.up()
画笔抬起 -- 移动时不画线。

turtle.pensize(width=None)
turtle.width(width=None)
参数 width -- 一个正数值
设置线条的粗细为 width 或返回该值。如果 resizemode 设为”auto” 并且 turtleshape 为多边形,该多边
形也以同样组细的线条绘制。如未指定参数,则返回当前的 pensize。

######################这是重点##########################################
turtle.pen(pen=None, **pendict)
参数
• pen -- 一个包含部分或全部下列键的字典
• pendict -- 一个或多个以下列键为关键字的关键字参数
返回或设置画笔的属性,以一个包含以下键值对的” 画笔字典” 表示:
• ”shown”: True/False
• ”pendown”: True/False
• ”pencolor”: 颜色字符串或颜色元组
• ”fillcolor”: 颜色字符串或颜色元组
• ”pensize”: 正数值
• ”speed”: 0..10 范围内的数值
• ”resizemode”: ”auto” 或”user” 或”noresize”
• ”stretchfactor”: (正数值, 正数值)
• ”outline”: 正数值
• ”tilt”: 数值
此字典可作为后续调用pen() 时的参数,以恢复之前的画笔状态。另外还可将这些属性作为关键
词参数提交。使用此方式可以用一条语句设置画笔的多个属性。
turtle.color(*args)
返回或设置画笔颜色和填充颜色。
允许多种输入格式。使用如下 0 至 3 个参数:
color() 返回以一对颜色描述字符串或元组表示的当前画笔颜色和填充颜色,两者可分别
由pencolor() 和fillcolor() 返回。
color(colorstring), color((r,g,b)), color(r,g,b) 输入格式与pencolor()相同,同
时设置填充颜色和画笔颜色为指定的值。
color(colorstring1, colorstring2), color((r1,g1,b1), (r2,g2,b2)) 相 当 于
pencolor(colorstring1) 加 fillcolor(colorstring2),使用其他输入格式的方法
也与之类似。
turtle.filling()
返回填充状态 (填充为 True,否则为 False)。
turtle.begin_fill()
在绘制要填充的形状之前调用。
turtle.end_fill()
填充上次调用begin_fill() 之后绘制的形状。
自相交多边形或多个形状间的重叠区域是否填充取决于操作系统的图形引擎、重叠的类型以及重
叠的层数。例如上面的 Turtle 多芒星可能会全部填充为黄色,也可能会有一些白色区域。

绘画总要有颜色嘛,以上是有关颜色的函数,我们来看一下示例:

#设置画笔状态,粗细为3,速度为10
turtle.pen(pensize=3,speed=10,)
#设置画笔颜色为red,填充颜色为yellow
turtle.color("red",'yellow')

angel=0
#开始填充
turtle.begin_fill()
for k in range(6):
    turtle.fd(50)
    angel += 60
    turtle.setheading(angel)
#结束填充
turtle.end_fill()

turtle.done()


弘扬中华民族文化,太极图必须要有:

#设置画笔状态,粗细为3,速度为10
turtle.pen(pensize=3,speed=10,)
#设置画笔颜色为black,填充颜色为black
turtle.color("black",'black')
#开始填充
turtle.begin_fill()
#半圆
turtle.circle(100,180)
#半径减半,再来个半圆
turtle.circle(50,180)
#根据海龟朝向,用负值在海龟右侧画半圆
turtle.circle(-50,180)
#填充阴部分
turtle.end_fill()
#根据海龟朝向,用负值在海龟右侧画整个圆
turtle.circle(-100)
#阴中有阳
turtle.penup()
turtle.goto(0,50)
turtle.pendown()
turtle.dot(30,"black")
#阳中有阴
turtle.penup()
turtle.goto(0,150)
turtle.pendown()
turtle.dot(30,"white")

turtle.done()

教程已过半,你悟了嘛?

既然是程序就要有交互,下面我么来写一个交互的界面:

turtle.textinput(title, prompt)
参数
• title -- string
• prompt -- string
弹出一个对话框窗口用来输入一个字符串。形参 title 为对话框窗口的标题,prompt 为一条文本,通
常用来提示要输入什么信息。返回输入的字符串。如果对话框被取消则返回 None。:

turtle.numinput(title, prompt, default=None, minval=None, maxval=None)
参数
• title -- string
• prompt -- string
• default -- 数值 (可选)
• minval -- 数值 (可选)
• maxval -- 数值 (可选)
弹出一个对话框窗口用来输入一个数值。title 为对话框窗口的标题,prompt 为一条文本,通常用来
描述要输入的数值信息。default: 默认值, minval: 可输入的最小值, maxval: 可输入的最大值。输入数
值的必须在指定的 minval .. maxval 范围之内,否则将给出一条提示,对话框保持打开等待修改。返
回输入的数值。如果对话框被取消则返回 None。

看以下示例,根据用户输入,配置画图设置,自己测试一下。

title = turtle.textinput("配置标题",'请输入你画图的窗口标题:')
speed = turtle.numinput("画笔速度设置","请输入画笔速度",minval=3,maxval=10)
penwidth = turtle.numinput("画笔宽度设置","请输入画笔宽度",minval=1,maxval=10)
width = turtle.numinput("画布设置",'画布宽度',minval=600,maxval=1280)
height = turtle.numinput("画布设置",'画布宽度',minval=600,maxval=960)

turtle.title(title)
turtle.pen(pensize=penwidth,speed=speed,)
#设置绘图窗口尺寸
turtle.setup(width=width,height=height)
#设置内部绘图区域大小,会出现滚动条,如果设置大于默认
#turtle.screensize(width,height)

turtle.done()

关于绘图窗口尺寸涉及到两个函数,大家可以分别设置一下,体会下不同:

turtle.screensize(canvwidth=None, canvheight=None, bg=None)
参数
• canvwidth -- 正整型数,以像素表示画布的新宽度值
• canvheight -- 正整型数,以像素表示画面的新高度值
• bg -- 颜色字符串或颜色元组,新的背景颜色
如未指定任何参数,则返回当前的 (canvaswidth, canvasheight)。否则改变作为海龟绘图场所的画布
大小。不改变绘图窗口。要观察画布的隐藏区域,可以使用滚动条。通过此方法可以令之前绘制于
画布之外的图形变为可见。
#########################################################################
turtle.setup(width=_CFG[’width’], height=_CFG[’height’], startx=_CFG[’leftright’],
starty=_CFG[’topbottom’])
设置主窗口的大小和位置。默认参数值保存在配置字典中,可通过 turtle.cfg 文件进行修改。
参数
• width -- 如为一个整型数值,表示大小为多少像素,如为一个浮点数值,则表示
屏幕的占比;默认为屏幕的 50%
• height -- 如为一个整型数值,表示高度为多少像素,如为一个浮点数值,则表
示屏幕的占比;默认为屏幕的 75%
• startx -- 如为正值,表示初始位置距离屏幕左边缘多少像素,负值表示距离右
边缘,None 表示窗口水平居中
• starty -- 如为正值,表示初始位置距离屏幕上边缘多少像素,负值表示距离下
边缘,None 表示窗口垂直居中

下面重点来了设置事件监听,先来熟悉下画笔的鼠标事件

turtle.onclick(fun, btn=1, add=None)
turtle.onscreenclick(fun, btn=1, add=None)
参数
• fun -- 一个函数,调用时将传入两个参数表示在画布上点击的坐标。
• btn -- 鼠标按钮编号,默认值为 1 (鼠标左键)
• add -- True 或 False -- 如为 True 则将添加一个新绑定,否则将取代先前的绑
定

turtle.onrelease(fun, btn=1, add=None)
参数
• fun -- 一个函数,调用时将传入两个参数表示在画布上点击的坐标。
• btn -- 鼠标按钮编号,默认值为 1 (鼠标左键)
• add -- True 或 False -- 如为 True 则将添加一个新绑定,否则将取代先前的绑
定
将 fun 指定的函数绑定到在此海龟上释放鼠标按键事件。如果 fun 值为 None,则移除现有的绑定。

turtle.ondrag(fun, btn=1, add=None)
参数
• fun -- 一个函数,调用时将传入两个参数表示在画布上点击的坐标。
• btn -- 鼠标按钮编号,默认值为 1 (鼠标左键)
• add -- True 或 False -- 如为 True 则将添加一个新绑定,否则将取代先前的绑
定
将 fun 指定的函数绑定到在此海龟上移动鼠标事件。如果 fun 值为 None,则移除现有的绑定。
注: 在海龟上移动鼠标事件之前应先发生在此海龟上点击鼠标事件。

下面一个示例,我们来做一个颜色调节器:

首先来看看我们将要用到的几个函数:

turtle.shape(name=None)
参数 name -- 一个有效的形状名字符串
设置海龟形状为 name 指定的形状名,如未指定形状名则返回当前的形状名。name 指定的形状名
应存在于 TurtleScreen 的 shape 字典中。多边形的形状初始时有以下几种: ”arrow”, ”turtle”, ”circle”,
”square”, ”triangle”, ”classic”。要了解如何处理形状请参看 Screen 方法register_shape()。


turtle.resizemode(rmode=None)
参数 rmode -- 字符串”auto”, ”user”, ”noresize” 其中之一
设置大小调整模式为以下值之一: ”auto”, ”user”, ”noresize”。如未指定 rmode 则返回当前的大小调整
模式。不同的大小调整模式的效果如下:
• ”auto”: 根据画笔粗细值调整海龟的外观。
• ”user”: 根据拉伸因子和轮廓宽度 (outline) 值调整海龟的外观,两者是由shapesize() 设置
的。
• ”noresize”: 不调整海龟的外观大小。


turtle.shapesize(stretch_wid=None, stretch_len=None, outline=None)
turtle.turtlesize(stretch_wid=None, stretch_len=None, outline=None)
参数
• stretch_wid -- 正数值
• stretch_len -- 正数值
• outline -- 正数值
返回或设置画笔的属性 x/y-拉伸因子和/或轮廓。设置大小调整模式为”user”。当且仅当大小调整
模式设为”user” 时海龟会基于其拉伸因子调整外观: stretch_wid 为垂直于其朝向的宽度拉伸因子,
stretch_len 为平等于其朝向的长度拉伸因子,决定形状轮廓线的粗细。

turtle.mode(mode=None)
参数 mode -- 字符串”standard”, ”logo” 或”world” 其中之一
设置海龟模式 (”standard”, ”logo” 或”world”) 并执行重置。如未指定模式则返回当前的模式。
”standard” 模式与旧的turtle 兼容。”logo” 模式与大部分 Logo 海龟绘图兼容。”world” 模式使用用
户自定义的” 世界坐标系”。注意: 在此模式下,如果 x/y 单位比率不等于 1 则角度会显得扭曲。
模式 初始海龟朝向 正数角度
”standard” 朝右 (东) 逆时针
”logo” 朝上 (北) 顺时针

turtle.colormode(cmode=None)
参数 cmode -- 数值 1.0 或 255 其中之一
返回颜色模式或将其设为 1.0 或 255。构成颜色三元组的 r, g, b 数值必须在 0..cmode 范围之内。


下面来看实例,为了方便大家分析代码,没有用任何循环,代码比较长,大家体会用法就好。

海龟绘图实现调色板

import turtle
   
#参数x,y必须要有,这是事件传过来的坐标
#根据y坐标调整背景颜色y坐标范围(0-255)
def change(x,y):
    rc = int(r.ycor())
    gc = int(g.ycor())
    bc = int(b.ycor())
    turtle.bgcolor(rc,gc,bc)
    
#为了保证海龟移动范围,在调节条内,固定x坐标
def rmove(x,y):
    if 0<=y<=255 :
        r.goto(-200,y)
def gmove(x,y):
    if 0<=y<=255 :
        g.goto(0,y)
def bmove(x,y):
    if 0<=y<=255 :
        b.goto(200,y)
        
    

#设置颜色模式取值范围0-255,方便后续设置背景色    
turtle.colormode(255)
#设置海龟图标为logo模式,头部朝上也就是北
turtle.mode("logo")
#设置海龟调整尺寸模式为user方便后续改变海龟形状
turtle.resizemode(rmode="user")
#隐藏默认的海龟图标,否则屏幕上会出现四个海龟
turtle.hideturtle()
#初始化背景颜色
turtle.bgcolor(255//2,255//2,255//2)

#红色海龟对象
r = turtle.Turtle()
#设置颜色,填充色,尺寸
r.pen(pencolor="red",fillcolor='red',pensize=5,)
#设置海龟显示形状为海龟图形
r.shape(name="turtle")
#设置海龟大小
r.turtlesize(3,3)
#移动至指定位置
r.penup()
r.goto(-200,0)
r.pendown()
r.fd(255)
r.bk(255/2)
#绑定海龟拖动事件
r.ondrag(rmove)
#绑定左键松开后事件
r.onrelease(change)

#以下是另外两个对象
g = turtle.Turtle()
g.pen(pencolor="green",fillcolor='green',pensize=5,)
g.shape(name="turtle")
g.turtlesize(3,3)
g.pendown()
g.fd(255)
g.bk(255/2)
g.pendown()
g.ondrag(gmove)
g.onrelease(change)


b = turtle.Turtle()
b.pen(pencolor="black",fillcolor='black',pensize=5,)
b.shape(name="turtle")
b.turtlesize(3,3)
b.penup()
b.goto(200,0)
b.pendown()
b.fd(255)
b.bk(255/2)
b.ondrag(bmove)
b.onrelease(change)

turtle.done()

我们绑定的是海龟事件,所以鼠标要点击或者拖动在海龟图标上,才会触发事件,那就要把海龟图标放大,后续还有屏幕事件。我们定义了三个海龟对象,也就是三个画笔,分别用于调整红色,绿色,黑色,然后组合到一起,当鼠标松开,改变背景颜色。

下面我们结合画板和画笔事件来实现一个简陋的画板小程序:
点击按钮可以输入画笔尺寸,按下空格,撤销画笔前一步操作

海龟绘图简易画板

import turtle

#帮助我们画出一个按钮
def rbutton(x,y,width =100,height =40,text="" ):
    myturtle.color('red','black')
    myturtle.penup()
    myturtle.goto(x,y)
    myturtle.pendown()
    myturtle.begin_fill()
    for i in range(2):
        myturtle.fd(width)
        myturtle.right(90)
        myturtle.fd(height)
        myturtle.right(90)
    myturtle.end_fill()
    myturtle.penup()
    myturtle.goto(x+20,(y+y-height)//2)
    myturtle.pendown()
    myturtle.write(text,align="left",font=('Arial', 8, 'bold'))
    myturtle.penup()
    myturtle.home()
    myturtle.pendown()
    return [(x,x+width),(y-height,y)]

#绑定画板事件设置画笔尺寸函数
def setpensize(x,y):
    if xrange[0]<x<xrange[1] and yrange[0] < y< yrange[1]:
        size=screen.numinput("画笔尺寸","请输入画笔尺寸",default=3,minval=3,maxval=15)
        myturtle.pensize(size)
    #设置完成必须再次把焦点转移到画板,否则按键事件无法触发
    screen.listen()
        
#绑定画板按键事件,撤销画笔操作
def cancel():
    myturtle.undo()
    
#为了方便大家区分,画笔对象和画板对象,我们分别新建一个画笔和画板对象
#画板对象
screen  = turtle.Screen()
#画笔对象
myturtle = turtle.Turtle()
#设置窗口尺寸
screen.setup(800,600)
#设置窗口标题
screen.title("简陋的调色板")
#为了方便设置,设置颜色模式
turtle.colormode(cmode=255)
#绑定空格键按下事件
screen.onkey(cancel,key='space')
#按键事件必须开启该监听函数
screen.listen()
#画出的按钮返回坐标范围
xrange, yrange = rbutton(-350,250,text="画笔尺寸")
#利用坐标范围触发画板事件,设置画笔尺寸
screen.onscreenclick(setpensize)
#设置画笔拖动事件为goto,拖动画笔自动画线
myturtle.ondrag(myturtle.goto)
screen.mainloop()

以上我们已经了解了,有关turtle的大部分功能,如果我们要编写比较负责的程序逻辑,就要利用turtle对象和screen对象,来进行面向对象编程。

接下来看几个官方示例:

from turtle import *

def main():
    peacecolors = ("red3",  "orange", "yellow",
                   "seagreen4", "orchid4",
                   "royalblue1", "dodgerblue4")

    reset()
    Screen()
    up()
    goto(-320,-195)
    width(70)

    for pcolor in peacecolors:
        color(pcolor)
        down()
        forward(640)
        up()
        backward(640)
        left(90)
        forward(66)
        right(90)

    width(25)
    color("white")
    goto(0,-170)
    down()

    circle(170)
    left(90)
    forward(340)
    up()
    left(180)
    forward(170)
    right(45)
    down()
    forward(170)
    up()
    backward(170)
    left(90)
    down()
    forward(170)
    up()

    goto(0,300) # vanish if hideturtle() is not available ;-)
    return "Done!"

if __name__ == "__main__":
    main()
    mainloop()

from turtle import Turtle, mainloop
from time import perf_counter as clock

def tree(plist, l, a, f):
    """ plist is list of pens
    l is length of branch
    a is half of the angle between 2 branches
    f is factor by which branch is shortened
    from level to level."""
    if l > 3:
        lst = []
        for p in plist:
            p.forward(l)
            q = p.clone()
            p.left(a)
            q.right(a)
            lst.append(p)
            lst.append(q)
        for x in tree(lst, l*f, a, f):
            yield None

def maketree():
    p = Turtle()
    p.setundobuffer(None)
    p.hideturtle()
    p.speed(0)
    p.getscreen().tracer(30,0)
    p.left(90)
    p.penup()
    p.forward(-210)
    p.pendown()
    t = tree([p], 200, 65, 0.6375)
    for x in t:
        pass

def main():
    a=clock()
    maketree()
    b=clock()
    return "done: %.2f sec." % (b-a)

if __name__ == "__main__":
    msg = main()
    print(msg)
    mainloop()

from turtle import *
from datetime import datetime

def jump(distanz, winkel=0):
    penup()
    right(winkel)
    forward(distanz)
    left(winkel)
    pendown()

def hand(laenge, spitze):
    fd(laenge*1.15)
    rt(90)
    fd(spitze/2.0)
    lt(120)
    fd(spitze)
    lt(120)
    fd(spitze)
    lt(120)
    fd(spitze/2.0)

def make_hand_shape(name, laenge, spitze):
    reset()
    jump(-laenge*0.15)
    begin_poly()
    hand(laenge, spitze)
    end_poly()
    hand_form = get_poly()
    register_shape(name, hand_form)

def clockface(radius):
    reset()
    pensize(7)
    for i in range(60):
        jump(radius)
        if i % 5 == 0:
            fd(25)
            jump(-radius-25)
        else:
            dot(3)
            jump(-radius)
        rt(6)

def setup():
    global second_hand, minute_hand, hour_hand, writer
    mode("logo")
    make_hand_shape("second_hand", 125, 25)
    make_hand_shape("minute_hand",  130, 25)
    make_hand_shape("hour_hand", 90, 25)
    clockface(160)
    second_hand = Turtle()
    second_hand.shape("second_hand")
    second_hand.color("gray20", "gray80")
    minute_hand = Turtle()
    minute_hand.shape("minute_hand")
    minute_hand.color("blue1", "red1")
    hour_hand = Turtle()
    hour_hand.shape("hour_hand")
    hour_hand.color("blue3", "red3")
    for hand in second_hand, minute_hand, hour_hand:
        hand.resizemode("user")
        hand.shapesize(1, 1, 3)
        hand.speed(0)
    ht()
    writer = Turtle()
    #writer.mode("logo")
    writer.ht()
    writer.pu()
    writer.bk(85)

def wochentag(t):
    wochentag = ["Monday", "Tuesday", "Wednesday",
        "Thursday", "Friday", "Saturday", "Sunday"]
    return wochentag[t.weekday()]

def datum(z):
    monat = ["Jan.", "Feb.", "Mar.", "Apr.", "May", "June",
             "July", "Aug.", "Sep.", "Oct.", "Nov.", "Dec."]
    j = z.year
    m = monat[z.month - 1]
    t = z.day
    return "%s %d %d" % (m, t, j)

def tick():
    t = datetime.today()
    sekunde = t.second + t.microsecond*0.000001
    minute = t.minute + sekunde/60.0
    stunde = t.hour + minute/60.0
    try:
        tracer(False)  # Terminator can occur here
        writer.clear()
        writer.home()
        writer.forward(65)
        writer.write(wochentag(t),
                     align="center", font=("Courier", 14, "bold"))
        writer.back(150)
        writer.write(datum(t),
                     align="center", font=("Courier", 14, "bold"))
        writer.forward(85)
        tracer(True)
        second_hand.setheading(6*sekunde)  # or here
        minute_hand.setheading(6*minute)
        hour_hand.setheading(30*stunde)
        tracer(True)
        ontimer(tick, 100)
    except Terminator:
        pass  # turtledemo user pressed STOP

def main():
    tracer(False)
    setup()
    tracer(True)
    tick()
    return "EVENTLOOP"

if __name__ == "__main__":
    mode("logo")
    msg = main()
    print(msg)
    mainloop()

重点注意这个实例,结合了tkinter,建立了两个画板对象,和画笔对象

from turtle import TurtleScreen, RawTurtle, TK

def main():
    root = TK.Tk()
    cv1 = TK.Canvas(root, width=300, height=200, bg="#ddffff")
    cv2 = TK.Canvas(root, width=300, height=200, bg="#ffeeee")
    cv1.pack()
    cv2.pack()

    s1 = TurtleScreen(cv1)
    s1.bgcolor(0.85, 0.85, 1)
    s2 = TurtleScreen(cv2)
    s2.bgcolor(1, 0.85, 0.85)

    p = RawTurtle(s1)
    q = RawTurtle(s2)

    p.color("red", (1, 0.85, 0.85))
    p.width(3)
    q.color("blue", (0.85, 0.85, 1))
    q.width(3)

    for t in p,q:
        t.shape("turtle")
        t.lt(36)

    q.lt(180)

    for t in p, q:
        t.begin_fill()
    for i in range(5):
        for t in p, q:
            t.fd(50)
            t.lt(72)
    for t in p,q:
        t.end_fill()
        t.lt(54)
        t.pu()
        t.bk(50)

    return "EVENTLOOP"


if __name__ == '__main__':
    main()
    TK.mainloop()  # keep window open until user closes it

from turtle import Shape, Turtle, mainloop, Vec2D as Vec

G = 8

class GravSys(object):
    def __init__(self):
        self.planets = []
        self.t = 0
        self.dt = 0.01
    def init(self):
        for p in self.planets:
            p.init()
    def start(self):
        for i in range(10000):
            self.t += self.dt
            for p in self.planets:
                p.step()

class Star(Turtle):
    def __init__(self, m, x, v, gravSys, shape):
        Turtle.__init__(self, shape=shape)
        self.penup()
        self.m = m
        self.setpos(x)
        self.v = v
        gravSys.planets.append(self)
        self.gravSys = gravSys
        self.resizemode("user")
        self.pendown()
    def init(self):
        dt = self.gravSys.dt
        self.a = self.acc()
        self.v = self.v + 0.5*dt*self.a
    def acc(self):
        a = Vec(0,0)
        for planet in self.gravSys.planets:
            if planet != self:
                v = planet.pos()-self.pos()
                a += (G*planet.m/abs(v)**3)*v
        return a
    def step(self):
        dt = self.gravSys.dt
        self.setpos(self.pos() + dt*self.v)
        if self.gravSys.planets.index(self) != 0:
            self.setheading(self.towards(self.gravSys.planets[0]))
        self.a = self.acc()
        self.v = self.v + dt*self.a

## create compound yellow/blue turtleshape for planets

def main():
    s = Turtle()
    s.reset()
    s.getscreen().tracer(0,0)
    s.ht()
    s.pu()
    s.fd(6)
    s.lt(90)
    s.begin_poly()
    s.circle(6, 180)
    s.end_poly()
    m1 = s.get_poly()
    s.begin_poly()
    s.circle(6,180)
    s.end_poly()
    m2 = s.get_poly()

    planetshape = Shape("compound")
    planetshape.addcomponent(m1,"orange")
    planetshape.addcomponent(m2,"blue")
    s.getscreen().register_shape("planet", planetshape)
    s.getscreen().tracer(1,0)

    ## setup gravitational system
    gs = GravSys()
    sun = Star(1000000, Vec(0,0), Vec(0,-2.5), gs, "circle")
    sun.color("yellow")
    sun.shapesize(1.8)
    sun.pu()
    earth = Star(12500, Vec(210,0), Vec(0,195), gs, "planet")
    earth.pencolor("green")
    earth.shapesize(0.8)
    moon = Star(1, Vec(220,0), Vec(0,295), gs, "planet")
    moon.pencolor("blue")
    moon.shapesize(0.5)
    gs.init()
    gs.start()
    return "Done!"

if __name__ == '__main__':
    main()
    mainloop()

来源:~白+黑

物联沃分享整理
物联沃-IOTWORD物联网 » python冲击二级—基本库turtle,海龟绘图详解,史上最全,没有之一

发表评论