✅作者简介:人工智能专业本科在读,喜欢计算机与编程,写博客记录自己的学习历程。
🍎个人主页: 小嗷犬的博客
🍊个人信条:为天地立心,为生民立命,为往圣继绝学,为万世开太平。
🥭本文内容:Python 海龟绘图:turtle库的使用
1.turtle简介
turtle
库是turtle绘图体系Python的实现,turtle库是python的标准库之一,属于入门级的图形绘制函数库。turtle库绘制原理:有一只海龟在窗体正中心,在画布上游走,走过的轨迹形成了绘制的图形,海龟由程序控制,可以自由改变颜色、方向宽度等。
2.turtle基础知识
2.1 画布
画布(canvas)就是turtle为我们展开用于绘图区域,我们可以设置它的 大小和 初始位置。我们可以通过
screensize
函数来设置画布的大小和背景颜色:
turtle.screensize(canvwidth=None, canvheight=None, bg=None)
其中screensize
函数的三个参数分别表示画布的宽、高和背景颜色。或者通过
setup
函数来设置:
turtle.setup(width=0.5, height=0.75, startx=None, starty=None)
其中参数width
,height
:输入宽和高为整数时, 表示像素;为小数时,表示占据电脑屏幕的比例。
(startx
,starty
): 这一坐标表示矩形窗口左上角顶点的位置,如果为空,则窗口位于屏幕中心。
2.2 画笔
2.2.1 画笔的状态
在画布上,默认有一个坐标原点为画布中心的坐标轴,坐标原点上有一只面朝x轴正方向小乌龟。这里我们描述小乌龟时使用了两个词语:坐标原点(位置),面朝x轴正方向(方向), turtle绘图中,就是使用位置方向描述小乌龟(画笔)的状态。
2.2.2 画笔的属性
画笔有 宽度、 颜色、 移动速度三个属性,分别可以通过以下函数来设置:
函数 | 描述 |
---|---|
turtle.pensize() | 设置画笔的宽度。 |
turtle.pencolor() | 没有参数时,返回当前画笔颜色;<br/>传入参数时,设置画笔颜色。 |
turtle.speed(speed) | 设置画笔移动速度,数字越大越快,当速度为0时为最快速。 |
2.2.3 绘图命令
操纵海龟绘图有着许多的命令,这些命令主要可以划分为3种:一种为 画笔运动命令,一种为 画笔控制命令,还有一种是 全局控制命令。
2.2.3.1 画笔运动命令
画笔运动命令如下:
命令 | 描述 |
---|---|
turtle.forward(distance) | 向当前画笔方向移动distance像素长度 |
turtle.backward(distance) | 向当前画笔相反方向移动distance像素长度 |
turtle.right(degree) | 顺时针移动degree° |
turtle.left(degree) | 逆时针移动degree° |
turtle.pendown()<br/>或turtle.pd() | 移动时绘制图形,缺省时也为绘制 |
turtle.goto(x,y) | 将画笔移动到坐标为x,y的位置 |
turtle.penup()<br/>或turtle.pu() | 提起笔移动,不绘制图形,用于另起一个地方绘制 |
turtle.circle() | 画圆,半径为正(负),表示圆心在画笔的左边(右边)画圆 |
setx( ) | 将当前x轴移动到指定位置 |
sety( ) | 将当前y轴移动到指定位置 |
setheading(angle) | 设置当前朝向为angle角度 |
home() | 设置当前画笔位置为原点,朝向水平向右 |
dot(r) | 绘制一个指定直径和颜色的圆点 |
值得一提的是
circle()
函数:
turtle.circle(radius, extent=None, steps=None)
它包含三个参数:
radius
表示半径,半径为正(负),表示圆心在画笔的左边(右边)画圆;extent
表示角度,360为一个整圆;step
为3时,表示绘制三角形。
2.2.3.2 画笔控制命令
画笔控制命令如下:
命令 | 描述 |
---|---|
turtle.fillcolor(colorstring) | 绘制图形的填充颜色 |
turtle.color(color1, color2) | 同时设置pencolor=color1, fillcolor=color2 |
turtle.filling() | 返回当前是否在填充状态 |
turtle.begin_fill() | 准备开始填充图形 |
turtle.end_fill() | 填充完成 |
turtle.hideturtle() | 隐藏画笔的turtle形状 |
turtle.showturtle() | 显示画笔的turtle形状 |
2.2.3.3 全局控制命令
全局控制命令如下:
命令 | 描述 |
---|---|
turtle.clear() | 清空turtle窗口,但是turtle的位置和状态不会改变 |
turtle.reset() | 清空窗口,重置turtle状态为起始状态 |
turtle.undo() | 撤销上一个turtle动作 |
turtle.isvisible() | 返回当前turtle是否可见 |
stamp() | 复制当前图形 |
turtle.write(s [,font=("font-name",font_size,"font_type")]) | 写文本,s为文本内容,font是字体的参数,分别为字体名称,大小和类型;font为可选项,font参数也是可选项 |
2.2.3.4 其他命令
除了上述的三种命令外,turtle库中还要一些不常用的命令:
命令 | 描述 |
---|---|
turtle.mainloop()或turtle.done() | 启动事件循环,调用Tkinter的mainloop函数。<br/>必须是海龟图形程序中的最后一个语句。 |
turtle.mode(mode=None) | 设置海龟模式(“standard”,“logo”或“world”)并执行重置。如果没有给出模式,则返回当前模式。 |
turtle.delay(delay=None) | 设置或返回以毫秒为单位的绘图延迟。 |
turtle.begin_poly() | 开始记录多边形的顶点。当前的海龟位置是多边形的第一个顶点。 |
turtle.end_poly() | 停止记录多边形的顶点。当前的海龟位置是多边形的最后一个顶点。将与第一个顶点相连。 |
turtle.get_poly() | 返回最后记录的多边形。 |
3.代码实例
3.1 哆啦A梦
下面的程序可以绘制出哆啦A梦:
import turtle
# 创建哆啦A梦
doraemon = turtle.Turtle()
doraemon.speed(10)
def draw_eye_white_circle(x):
doraemon.goto(x, 80)
doraemon.pendown()
doraemon.color('black')
doraemon.begin_fill()
doraemon.circle(15)
doraemon.color('white')
doraemon.end_fill()
def draw_eye_black_circle(x):
doraemon.goto(x, 90)
doraemon.color('black')
doraemon.begin_fill()
doraemon.begin_fill()
doraemon.circle(6)
doraemon.end_fill()
doraemon.penup()
# 画蓝色圆
doraemon.color('#0093dd')
doraemon.begin_fill()
doraemon.circle(60)
doraemon.end_fill()
# 画白色圆
doraemon.begin_fill()
doraemon.circle(50)
doraemon.color('white')
doraemon.end_fill()
# 画右眼白
draw_eye_white_circle(15)
# 画右眼黑
draw_eye_black_circle(6)
# 画左眼白
draw_eye_white_circle(-15)
# 画左眼黑
draw_eye_black_circle(-24)
# 画鼻子
doraemon.goto(0, 60)
doraemon.pendown()
doraemon.color('#c70000')
doraemon.begin_fill()
doraemon.circle(8)
doraemon.end_fill()
doraemon.color('black')
# 设置朝向(对应上北下南,左西右东)
# 0 为东,90 为北,180 为西,270 为南(同 -90)
doraemon.setheading(-90)
# 沿着刚刚设定的朝下方向绘制 40px
doraemon.forward(40)
doraemon.penup()
# 画嘴巴
doraemon.goto(-30, 40)
doraemon.pendown()
doraemon.circle(30, 180)
doraemon.penup()
doraemon.goto(0, 0)
turtle.Screen().exitonclick()
效果图:
3.2 动态时钟
下面的程序可以绘制出动态时钟:
import turtle
from datetime import *
# 抬起画笔,向前运动一段距离放下
def Skip(step):
turtle.penup()
turtle.forward(step)
turtle.pendown()
def mkHand(name, length):
# 注册Turtle形状,建立表针Turtle
turtle.reset()
Skip(-length * 0.1)
# 开始记录多边形的顶点。当前的乌龟位置是多边形的第一个顶点。
turtle.begin_poly()
turtle.forward(length * 1.1)
# 停止记录多边形的顶点。当前的乌龟位置是多边形的最后一个顶点。将与第一个顶点相连。
turtle.end_poly()
# 返回最后记录的多边形。
handForm = turtle.get_poly()
turtle.register_shape(name, handForm)
def Init():
global secHand, minHand, hurHand, printer
# 重置Turtle指向北
turtle.mode("logo")
# 建立三个表针Turtle并初始化
mkHand("secHand", 135)
mkHand("minHand", 125)
mkHand("hurHand", 90)
secHand = turtle.Turtle()
secHand.shape("secHand")
minHand = turtle.Turtle()
minHand.shape("minHand")
hurHand = turtle.Turtle()
hurHand.shape("hurHand")
for hand in secHand, minHand, hurHand:
hand.shapesize(1, 1, 3)
hand.speed(0)
# 建立输出文字Turtle
printer = turtle.Turtle()
# 隐藏画笔的turtle形状
printer.hideturtle()
printer.penup()
def SetupClock(radius):
# 建立表的外框
turtle.reset()
turtle.pensize(7)
for i in range(60):
Skip(radius)
if i % 5 == 0:
turtle.forward(20)
Skip(-radius - 20)
Skip(radius + 20)
if i == 0:
turtle.write(int(12), align="center",
font=("Courier", 14, "bold"))
elif i == 30:
Skip(25)
turtle.write(int(i/5), align="center",
font=("Courier", 14, "bold"))
Skip(-25)
elif (i == 25 or i == 35):
Skip(20)
turtle.write(int(i/5), align="center",
font=("Courier", 14, "bold"))
Skip(-20)
else:
turtle.write(int(i/5), align="center",
font=("Courier", 14, "bold"))
Skip(-radius - 20)
else:
turtle.dot(5)
Skip(-radius)
turtle.right(6)
def Week(t):
week = ["星期一", "星期二", "星期三",
"星期四", "星期五", "星期六", "星期日"]
return week[t.weekday()]
def Date(t):
y = t.year
m = t.month
d = t.day
return "%s %d %d" % (y, m, d)
def Tick():
# 绘制表针的动态显示
t = datetime.today()
second = t.second + t.microsecond * 0.000001
minute = t.minute + second / 60.0
hour = t.hour + minute / 60.0
secHand.setheading(6 * second)
minHand.setheading(6 * minute)
hurHand.setheading(30 * hour)
turtle.tracer(False)
printer.forward(65)
printer.write(Week(t), align="center",
font=("Courier", 14, "bold"))
printer.back(130)
printer.write(Date(t), align="center",
font=("Courier", 14, "bold"))
printer.home()
turtle.tracer(True)
# 100ms后继续调用tick
turtle.ontimer(Tick, 100)
# 打开/关闭龟动画,并为更新图纸设置延迟。
turtle.tracer(False)
Init()
SetupClock(160)
turtle.tracer(True)
Tick()
turtle.mainloop()
静态效果图:
3.3 小樱花树
下面的程序可以绘制出小樱花树:
import turtle
import random
# 画樱花的躯干(60,t)
def Tree(branch, t):
if branch > 3:
if 8 <= branch <= 12:
if random.randint(0, 2) == 0:
t.color('snow') # 白
else:
t.color('lightcoral') # 淡珊瑚色
t.pensize(branch / 3)
elif branch < 8:
if random.randint(0, 1) == 0:
t.color('snow')
else:
t.color('lightcoral') # 淡珊瑚色
t.pensize(branch / 2)
else:
t.color('sienna') # 赭色
t.pensize(branch / 10)
t.forward(branch)
a = 1.5 * random.random()
t.right(20 * a)
b = 1.5 * random.random()
Tree(branch - 10 * b, t)
t.left(40 * a)
Tree(branch - 10 * b, t)
t.right(20 * a)
t.up()
t.backward(branch)
t.down()
# 掉落的花瓣
def Petal(m, t):
for i in range(m):
a = 200 - 400 * random.random()
b = 10 - 20 * random.random()
t.up()
t.forward(b)
t.left(90)
t.forward(a)
t.down()
t.color('lightcoral') # 淡珊瑚色
t.circle(1)
t.up()
t.backward(a)
t.right(90)
t.backward(b)
# 绘图区域
t = turtle.Turtle()
# 画布大小
w = turtle.Screen()
t.hideturtle() # 隐藏画笔
t.getscreen().tracer(5, 0)
w.screensize(bg='wheat') # wheat小麦
t.left(90)
t.up()
t.backward(150)
t.down()
t.color('sienna')
# 画樱花的躯干
Tree(60, t)
# 掉落的花瓣
Petal(200, t)
w.exitonclick()
效果图:
3.4 飘落樱花树
下面的程序可以绘制出飘落樱花树(绘制时间较长,默认隐藏绘制过程):
from turtle import *
from random import *
from math import *
def tree(n,l):
pd()#下笔
#阴影效果
t = cos(radians(heading()+45))/8+0.25
pencolor(t,t,t)
pensize(n/3)
forward(l)#画树枝
if n>0:
b = random()*15+10 #右分支偏转角度
c = random()*15+10 #左分支偏转角度
d = l*(random()*0.25+0.7) #下一个分支的长度
#右转一定角度,画右分支
right(b)
tree(n-1,d)
#左转一定角度,画左分支
left(b+c)
tree(n-1,d)
#转回来
right(c)
else:
#画叶子
right(90)
n=cos(radians(heading()-45))/4+0.5
pencolor(n,n*0.8,n*0.8)
circle(3)
left(90)
#添加0.3倍的飘落叶子
if(random()>0.7):
pu()
#飘落
t = heading()
an = -40 +random()*40
setheading(an)
dis = int(800*random()*0.5 + 400*random()*0.3 + 200*random()*0.2)
forward(dis)
setheading(t)
#画叶子
pd()
right(90)
n = cos(radians(heading()-45))/4+0.5
pencolor(n*0.5+0.5,0.4+n*0.4,0.4+n*0.4)
circle(2)
left(90)
pu()
#返回
t=heading()
setheading(an)
backward(dis)
setheading(t)
pu()
backward(l)#退回
bgcolor(0.5,0.5,0.5)#背景色
ht()#隐藏turtle
speed(0)#速度 1-10渐进,0 最快
tracer(0,0)#注释本行可以显示出绘制过程
pu()#抬笔
backward(100)
left(90)#左转90度
pu()#抬笔
backward(300)#后退300
tree(12,100)#递归7层
done()
效果图:
3.5 圣诞树
下面的程序可以绘制出圣诞树(绘制时间较长,默认隐藏绘制过程):
from turtle import *
import random
n = 100.0
speed(0)
screensize(bg='seashell')
tracer(0, 0) # 注释本行显示绘制过程
left(90)
forward(3*n)
color("orange", "yellow")
begin_fill()
left(126)
for i in range(5):
forward(n/5)
right(144)
forward(n/5)
left(72)
end_fill()
right(126)
color("dark green")
backward(n*4.8)
def tree(d, s):
if d <= 0: return
forward(s)
tree(d-1, s*.8)
right(120)
tree(d-3, s*.5)
right(120)
tree(d-3, s*.5)
right(120)
backward(s)
tree(15, n)
backward(n/2)
for i in range(200):
a = 200 - 400 * random.random()
b = 10 - 20 * random.random()
up()
forward(b)
left(90)
forward(a)
down()
if random.randint(0, 1) == 0:
color('tomato')
else:
color('wheat')
circle(2)
up()
backward(a)
right(90)
backward(b)
done()
效果图: