我心中的王者:Python-海龟绘图
我心中的王者:Python-海龟绘图
海龟绘图是一个很早期的绘图函数库,出现在1966年的Logo计算机语言,在笔者学生时期就曾经使用Logo语言控制海龟绘图。很高兴现在已经成为Python的模块,我们可以使用它绘制计算机图形。与先前介绍的绘图模块比较,最大的差异在我们可以看到海龟绘图的过程,增加动画效果。
31-1 基本观念与安装模块
海龟有3个关键属性,方向、位置和笔,笔也有属性,色彩、宽度和开/关状态。海龟绘图是Python内置的模块,使用前需导入此模块。
import turtle
31-2 绘图初体验
可以使用Pen( )设定海龟绘图对象,例如:
t = turtle.Pen( )
上述代码执行后,就可以建立画布,同时屏幕中间就可以看到箭头(arrow),这就是所谓的海龟,31-6节笔者将列出所有海龟外型。例如,右图是使用Python Shell执行时的画面。
在海龟绘图中,画布中央是(0,0),往右x轴递增往左x轴递减,往上y轴递增往下y轴递减,海龟的起点在(0,0)位置,移动的单位是像素(pixel)。如果现在输入右图指令,可以看到海龟在Python Turtle Graphics画布上绘图。
上述我们画了一个正方形,其实每输入一条指令,都可以看到海龟转向或前进绘图。
31-3 绘图基本练习
下列是海龟绘图基本方法的说明表。
程序实例ch31_1.py:使用海龟绘制正方形。
# ch31_1.py
import turtle
t = turtle.Pen()
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
执行结果
其实适度使用循环,可以创造一些有趣的图。
程序实例ch31_2.py:绘制五角星。
# ch31_2.py
import turtle
t = turtle.Pen()
for x in range(1, 6):
t.forward(100)
t.left(144)
执行结果
程序实例ch31_3.py:绘制有趣图形,这次将旋转角度改成顺时针。
# ch31_3.py
import turtle
t = turtle.Pen()
for x in range(1, 20):
t.forward(100)
t.right(170)
执行结果
程序实例ch31_4.py:绘制有趣图形。
# ch31_4.py
import turtle
t = turtle.Pen()
for x in range(1, 40):
t.forward(200)
t.right(95)
执行结果
程序实例ch31_5.py:绘制有趣图形。
# ch31_5.py
import turtle
t = turtle.Pen()
for x in range(1, 500):
t.forward(x)
t.right(91)
执行结果
程序实例ch31_6.py:绘制有趣图形。
# ch31_6.py
import turtle
t = turtle.Pen()
for x in range(1, 37):
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(100)
执行结果
31-4 控制画笔色彩与线条粗细
可以参考下面列表。
由上图可知,色彩处理时我们可以使用选择彩色画笔pencolor( ),也可以直接用color( )方法更改目前画笔的颜色,color( )方法的颜色可以是r,g,b组合,也可以是色彩字符串。在选择画笔粗细时可以使用pensize( ),也可以使用width( )。
程序实例ch31_7.py:这个程序是重新设计ch31_6.py,首先将画笔粗细改为5,其次在使用循环绘图时,r=0.5, g=1, b则是由1逐渐变小。
# ch31_7.py
import turtle
t = turtle.Pen()
t.pensize(5) # 画笔宽度
colorValue = 1.0
colorStep = colorValue / 36
for x in range(1, 37):
colorValue -= colorStep
t.color(0.5, 1, colorValue) # 色彩调整
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(100)
执行结果
程序实例ch31_8.py:使用不同颜色与不同粗细画笔的应用。
# ch31_8.py
import turtle
t = turtle.Pen()
colorsList = ['red','orange','yellow','green','blue','cyan','purple','violet']
tWidth = 1 # 最初画笔宽度
for x in range(1, 41):
t.color(colorsList[x % 8]) # 选择画笔颜色
t.forward(2 + x * 5) # 每次移动距离
t.right(45) # 每次旋转角度
tWidth += x * 0.05 # 每次画笔宽度递增
t.width(tWidth)
执行结果
31-5 绘制圆或弧形
要绘制圆可以使用circle®,r是圆半径。绘制圆时当前海龟面对方向的左侧半径位置将是圆的中心。例如,海龟在(0,0)位置,海龟方向是向东,则绘制半径为50的圆时,圆中心是在(0,50)的位置。如果半径是正值绘制圆时是海龟目前位置开始以逆时针方式绘制,如果半径是负值,则绘制圆时是从海龟目前位置开始以顺时针方式绘制。
程序实例ch31_9.py:绘制4个圆其中半径是50或-50各2个,海龟位置是(0,0)与(100,0)。
# ch31_9.py
import turtle
t = turtle.Pen()
t.circle(50) # 绘制第1个左上方圆
t.circle(-50) # 绘制第2个左下方圆
t.forward(100)
t.circle(50) # 绘制第3个右上方圆
t.circle(-50) # 绘制第4个右下方圆
执行结果
程序实例ch31_10.py:绘制同心圆。
# ch31_10.py
import turtle
t = turtle.Pen()
step = 5 # 每次增加距离
for r in range(10, 50, step):
t.circle(r) # 绘制圆
t.penup() # 将笔提起
t.right(90) # 方向往下
t.forward(step) # 移动海龟位置起绘点
t.right(270) # 方向往右
t.pendown() # 将笔放下准备绘制
执行结果
上述penup( )将笔提起不绘制任何线条也可想成关闭笔,pendown( )将笔放下准备画图也可想成打开笔。在circle( )方法内若是有第2个参数,如果这个参数是360,则是一个圆;如果是180,则是半个圆弧。
程序实例ch31_11.py:绘制弧度的应用。
# ch31_11.py
import turtle
t = turtle.Pen()
step = 5 # 每次增加距离
for r in range(10, 90, step):
t.circle(r, 90 + r*2) # 绘制圆
t.penup() # 将笔提起
t.home() # 海龟回到原点(0,0)
t.pendown() # 将笔放下准备绘制
执行结果
程序实例ch31_12.py:基本上是重新设计ch31_10.py,但是使用不同颜色与线条宽度,每次循环线条宽度加1的应用。
# ch31_12.py
import turtle
t = turtle.Pen()
colors = ['red', 'orange', 'yellow', 'green', 'blue']
step = 10 # 每次增加距离
twidth = 0 # 最初宽度0
for r in range(1, 11):
t.color(colors[r % 5]) # 选画笔颜色
twidth += 1 # 每次循环宽度加1
t.width(twidth) # 设定宽度
t.circle(r*step) # 绘制圆
t.penup() # 将笔关闭
t.right(90) # 方向往下
t.forward(step) # 移动海龟位置起绘点
t.right(270) # 方向往右
t.pendown() # 将笔开启准备绘制
执行结果
程序实例ch31_13.py:绘制圆线条的应用。
# ch31_13.py
import turtle
t = turtle.Pen()
t.color('blue')
for angle in range(0, 360, 15):
t.setheading(angle) # 调整海龟方向
t.circle(100)
执行结果
上述用到了一个尚未讲解的方法setheading( ),也可以缩写seth( ),这是调整海龟方向,海龟初始是向右,相当于0度。
31-6 认识与操作海龟图像
在trutle模块内shape(‘turtle’)方法可以让海龟呈现,stamp( )可以使用海龟在画布盖章。
程序实例ch31_14.py:让海龟呈现同时在画布盖章。
# ch31_14.py
import turtle
t = turtle.Pen()
t.color('blue')
t.shape('turtle')
for angle in range(0, 361, 15):
t.forward(100)
t.stamp()
t.home()
t.seth(angle) # 调整海龟方向
执行结果
clearstamps(n)如果n=None可以清除画布上所有的海龟,如果n是正值可以清除前n个海龟,如果n是负值可以清除后n个海龟。如果海龟在画布盖章时有设定返回值,例如,stampID=t.stamp( ),未来也可以使用clearstamp(stampID)将这个特定的海龟盖章删除。
程序实例ch31_15.py:这个程序首先将绘制3个海龟(第7~11行),然后将自己隐藏(第12行),过5秒先删除第2只海龟(第14行),再过5秒将删除其他2只海龟(第16行)。
# ch31_15.py
import turtle, time
t = turtle.Pen()
t.color('blue')
t.shape('turtle')
firstStamp = t.stamp() # 盖章第1只海龟
t.forward(100)
secondStamp = t.stamp() # 盖章第2只海龟
t.forward(100)
thirdStamp = t.stamp() # 盖章第3只海龟
t.hideturtle() # 隐藏目前海龟
time.sleep(5)
t.clearstamp(secondStamp) # 删除第2只海龟
time.sleep(5)
t.clearstamps(None) # 删除所有海龟
执行结果 下列分别是显示3只海龟,删除第2只后剩2只以及全部删除的结果。
31-6-1 隐藏与显示海龟
上述第12行hideturtle( )是隐藏海龟,未来若是想显示海龟可以使用showturtle( )方法。isvisible( )可以检查目前程序是否有显示海龟,如果有显示可以返回True,如果没有显示则返回False。
程序实例ch31_16.py:这个程序会先盖章第1只海龟(第7行),第8行是打印是否显示海龟光标,结果是True。然后盖章第2只海龟(第10行),隐藏海龟光标,所以第13行打印是否显示海龟光标,结果是False。第14行是删除最后一只海龟,相当于是删除第2只海龟。第16行是显示海龟光标,所以第17行打印是否显示海龟光标,结果是True。
# ch31_16.py
import turtle, time
t = turtle.Pen()
t.color('blue')
t.shape('turtle')
t.stamp() # 盖章第1只海龟
print("目前有显示海龟 : ", t.isvisible())
t.forward(100)
secondStamp = t.stamp() # 盖章第2只海龟
time.sleep(3)
t.hideturtle() # 隐藏目前海龟
print("目前有显示海龟 : ", t.isvisible())
t.clearstamps(-1) # 删除后面1个海龟
time.sleep(3)
t.showturtle() # 显示海龟
print("目前有显示海龟 : ", t.isvisible())
执行结果
目前有显示海龟 : True
目前有显示海龟 : False
目前有显示海龟 : True
31-6-2 认识所有的海龟光标
screen.getshapes( )方法可以列出所有的海龟光标。
程序实例ch31_17.py:列出所有海龟光标字符串,与相对应的光标外型。
# ch31_17.py
import turtle, time
t = turtle.Pen()
t.color('blue')
print(t.screen.getshapes()) # 打印海龟光标字符串
for cursor in t.screen.getshapes():
t.shape(cursor) # 更改海龟光标
t.stamp() # 海龟游标盖章
t.forward(30)
执行结果
我们也可以使用下列方式将任意图片当作海龟光标,不过图片不会在我们转动海龟时随着转动。
screen.register_shape(“图片名称”)
或者我们也可以使用下列方式自建一个外型当海龟光标。
screen.(‘myshape', ((3,-3),(0,3),(-3,-3)))
31-7 填满颜色
可以参考下表。
在程序设计时,也可以使用color( )包含2个参数,分别代表图形轮廓与内部颜色。
程序实例ch31_18.py:设计填充2个圆,第一个填充轮廓颜色是蓝色填充颜色是黄色,分成5和6行撰写。第二个填充轮廓颜色是红色填充颜色是海蓝色,在第11行撰写。
# ch31_18.py
import turtle
t = turtle.Pen()
t.color('blue') # 设定轮廓颜色
t.fillcolor('yellow') # 设定填充颜色
t.begin_fill() # 开始填充
t.circle(50) # 绘制左方圆
t.end_fill() # 结束填充
t.forward(100)
t.color('red', 'aqua') # 设定轮廓颜色是red, 填充颜色是aqua
t.begin_fill() # 开始填充
t.circle(50) # 绘制第2个右方圆
t.end_fill() # 结束填充
执行结果
程序实例ch31_19.py:填充矩形的应用,轮廓宽度是5颜色是蓝色,所填充的是黄色。
# ch31_19.py
import turtle
t = turtle.Pen()
t.color('blue') # 设定轮廓颜色
t.width(5) # 轮廓宽度
t.fillcolor('yellow') # 设定填充颜色
t.begin_fill() # 开始填充
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.forward(100)
t.left(90)
t.end_fill() # 结束填充
执行结果
31-8 颜色动画的设计
其实我们可以每隔一段时间更改填充区间颜色,达到颜色区间动画设计。
程序实例ch31_20.py:每隔3秒更改填充的颜色。
# ch31_20.py
import turtle, time
colorsList = ['green', 'yellow', 'red']
t = turtle.Pen()
for i in range(0,3):
t.fillcolor(colorsList[i%3]) # 更改色彩
t.begin_fill() # 开始填充
t.circle(50) # 绘制左方圆
t.end_fill() # 结束填充
time.sleep(3) # 每隔3秒执行一次循环
执行结果 下列分别是每隔3秒的执行结果。
如果我们使用白色绘制圆轮廓可以达到隐藏轮廓颜色,若是再隐藏海龟光标,整个效果将更好。
程序实例ch31_21.py:隐藏轮廓线和海龟(第7行),重新设计ch31_20.py,程序第9行使用白色线条绘制轮廓线相当于隐藏了轮廓,同时用指定颜色填满圆。
# ch31_21.py
import turtle, time
colorsList = ['green', 'yellow', 'red']
t = turtle.Pen()
t.speed(10) # 加速绘制图形
t.ht() # 隐藏海龟游标
for i in range(0,3):
t.color('white', colorsList[i%3]) # 更改色彩
t.begin_fill() # 开始填充
t.circle(50) # 绘制左方圆
t.end_fill() # 结束填充
time.sleep(3) # 每隔3秒执行一次循环
执行结果
31-9 绘图窗口的相关知识
下列是相关方法使用表:
31-9-1 更改海龟窗口标题与背景颜色
程序实例ch31_22.py:默认窗口标题是Python Turtle Graphics,这个程序会更改窗口标题为Python王者归来,同时设定背景颜色是黄色。
# ch31_22.py
import turtle
t = turtle.Pen()
t.screen.title('Python王者归来')
t.screen.bgcolor('yellow')
执行结果
31-9-2 取得/更改窗口宽度与高度
程序实例ch31_23.py:分别传回海龟窗口的宽度与高度,3秒后这个程序会更改窗口宽度与高度分别为600与480。
# ch31_23.py
import turtle,time
t = turtle.Pen()
width = t.screen.window_width()
height = t.screen.window_height()
print("窗口width = ", width)
print("窗口height = ", height)
time.sleep(3)
t.screen.setup(600, 480) # 更改窗口宽和高
width = t.screen.window_width()
height = t.screen.window_height()
print("新窗口width = ", width)
print("新窗口height = ", height)
执行结果 读者可以在屏幕看到窗口大小更改结果。
窗口width = 640
窗口height = 600
新窗口width = 600
新窗口height = 480
31-9-3 重设世界坐标
当使用screen.setworldcoordinates( )重设海龟窗口为世界坐标时,海龟光标位置仍是在(0,0)。
程序实例ch31_24.py:重设海龟窗口为世界坐标时,让窗口左下角坐标是(0,0),先打印目前海龟光标坐标,然后画一条左下到右上的线,最后再打印一次当前海龟光标坐标。
# ch31_24.py
import turtle,time
t = turtle.Pen()
t.screen.setworldcoordinates(0,0,800,800)
print("打印海龟位置 = ", t.pos())
t.left(45)
t.forward(300)
print("打印新海龟位置 = ", t.pos())
执行结果
打印海龟位置 = (0.00,0.00)
打印新海龟位置 = (212.13,212.13)
31-10 文字的输出
可以使用write( )输出文字。
write(arg, move=False, align="left", font=( ))
arg是要写入海龟窗口的文字对象,move默认是False,如果是True画笔将移到本文右下角,align是“left”“center”或“right”。如果想自定义字体,可以在font=( )内设定(fontname, fontsize,fonttype)。
程序实例ch31_25.py:绘制时钟,同时在时钟上方输出文字。
# ch31_25.py
import turtle
t = turtle.Pen()
t.shape('turtle')
# 绘制时钟中间颜色
t.color('white', 'aqua')
t.setpos(0, -120)
t.begin_fill()
t.circle(120) # 会时钟内圆盘
t.end_fill()
t.penup() # 画笔关闭
t.home()
t.pendown() # 画笔打开
t.color('black')
t.pensize(5)
# 绘制时钟刻度
for i in range(1, 13):
t.penup() # 画笔关闭
t.seth(-30*i+90) # 设定刻度的角度
t.forward(180)
t.pendown() # 画笔打开
t.forward(30) # 画时间轴
t.penup()
t.forward(20)
t.write(str(i), align="left") # 写上刻度
t.home()
# 绘制时钟外框
t.home()
t.setpos(0, -270)
t.pendown()
t.pensize(10)
t.pencolor('blue')
t.circle(270)
# 写上名字
t.penup()
t.setpos(0, 320)
t.pendown()
t.write('Python王者归来', align="center", font=('新细明体', 24))
t.ht() # 隐藏游标
执行结果
31-11 鼠标与键盘信号
Python的turtle模块也提供简单的方法可以允许我们在Python Turtle Graphics窗口接收鼠标按键信号,然后可以设计成是针对这些信号做出反应。
31-11-1 onclick( )
这个方法主要是在Python Turtle Graphics窗口有鼠标按键发生时,会执行参数的内容,而所放的参数是我们设计的函数:
onclick(fun, btn=1, add=None)
fun是发生onclick事件时所要执行的函数名称,它会传递按键发生的x,y位置给fun函数,btn默认是鼠标左键,可参考下列实例说明。
程序实例ch31_26.py:当在Python Turtle Graphics窗口有按键发生时,在Python的Python Shell窗口将列出鼠标光标被按的x,y位置。下列是笔者在Python Turtle Graphics窗口单击鼠标键时的位置。
# ch31_26.py
import turtle
def printStr(x, y):
print(x, y)
t = turtle.Pen()
t.screen.onclick(printStr)
t.screen.mainloop()
执行结果
48.0 16.0
-5.0 -14.0
-27.0 114.0
-194.0 16.0
-150.0 -78.0
上述screen.mainloop( )方法必须在程序最后一行,让程序不结束,直到Python Turtle Graphics窗口关闭,才执行结束。
程序实例ch31_27.py:当在x轴大于0位置单击,绘半径是50的黄色圆,如果在x轴小于0位置单击,绘制半径为50的蓝色圆。
# ch31_27.py
import turtle
def drawSignal(x, y):
if x > 0:
t.fillcolor('yellow')
else:
t.fillcolor('blue')
t.penup()
t.setpos(x,y-50) # 设定绘圆起点
t.begin_fill()
t.circle(50)
t.end_fill()
t = turtle.Pen()
t.screen.onclick(drawSignal)
t.screen.mainloop()
执行结果
31-11-2 onkey( )和listen( )
onkey( )主要是关注键盘的信号,语法如下:
onkey(fun, key) # fun是所要执行的函数,key是键盘按键
onkey( )无法单独运作,需要listen( )倾听将信号传给onkey( )。
程序实例ch31_28.py:单击up键海龟往上移50,单击down键海龟往下移50。
# ch31_28.py
import turtle
def keyUp():
t.seth(90)
t.forward(50)
def keyDn():
t.seth(270)
t.forward(50)
t = turtle.Pen()
t.screen.onkey(keyUp, 'Up')
t.screen.onkey(keyDn, 'Down')
t.screen.listen()
t.screen.mainloop()
执行结果
作者:andyyah晓波