python上手--玩转Turtle

python上手--玩转Turtle

Turtle模块绝对是吸引非专业代码开发者人员学习python入门的好工具,通过turtle几行代码的执行软件就会画出漂亮的图形,美观而且有成就感,这样一下子对python编程就产生了兴趣。这些漂亮的图形如三角形、五角星、机器猫等。在写代码的时候改变几个参数,就可以产生新的奇形怪状,小朋友们遇到这样的情形绝对会向家长或者老师炫耀。下面我就以玩转Turtle为题进入本篇的介绍。

什么是Turtle?

Turtle英译过来为乌龟,不过我们介绍的不是这种动物,而是以此命名的一个绘图软件。在python文档中介绍了Turtle本身是一款简单、易上手的绘图软件,非常适合带领孩子们进入编程的世界。该软件由Wally Feurzeig, Seymour Papert and Cynthia Solomon等在1967年使用最原始的Logo编程语言开发而成。python语言出现后,有开发者使用python对其进行了重写,变成了Python内置的一个模块。随着python语言的大热,Turtle模块也成为了python语言简单好用的一个代名词,或者说一个很好的宣讲案例。在Python中,使用turtle模块的几行代码、改变几个参数就能绘出漂亮的图形,如果再增加一些参数,还能绘制出如笑脸、哆啦A梦、表情包等创意十足的图像,令人惊叹。在学着绘图时,就会逐步学习python的一些基本语法、函数、模块、类和对象等基础知识;边玩边学四字成语非常恰当的描述了玩转turtle模块的境界,也非常适宜于少儿或者初学者进入Python的世界。

如何玩Turtle?

当然在这里需要进入python编程环境,可以直接使用IDLE新建一个python文件,命名为turtle1.py。然后在这个python文件中就可以开始动手写有关turtle的代码。

Turtle是python安装时自带的内置模块,调用该模块非常简单,直接使用import方式加载:

import turtle

这也是程序的第一行代码,用于准备好使用turtle这个模块。

(1)基本动作和转向

然后就可以开始学步了。首先从走开始,让乌龟往前走100步,就在第一行代码结束后在第二行代码处写入:

turtle.forward(100)

这里forward就是往前走的方法,括号里的100为设定的步伐参数。

此时如果运行该程序,就可以看到一张画布弹出来,该画布左上角有Python Turtle Graphics标题和LOGO,在画布的中部黑三角箭头正按照较快的速度往前挪,很快到达100步那个位置。前进的过程就像一支黑色的笔在画布上按照设定方式在画画,笔头安装了一个黑色箭头用于指示方向,非常生动有趣。如下图:

而此时代码看起来是这样的:

如果想往前走300步,直接修改那个100为新的300即可。

即对于forward(参数)方法,括号里的参数是可以修改的,这在python程序里forward就是一个公用函数,其中的参数为变量,即值可以改变的参数。控制了这个参数,就可以控制前进的距离。

如果想回撤,那么就可以使用乌龟的backward方法。如在上述代码第三行加入回撤50步的代码,如下:

import turtle
turtle.forward(100)
turtle.backward(50)

保存新的文件同时运行,可以看到画布上画笔的黑三角箭头保持方向不变,但倒着往回50步。如图:

上述forward和backward就是前进和后退的方法,两种方法都有括号,在括号里可以设定前进或后退的步伐(这里一步为画布上的一个像素点)。

只有前进和后退显然有点单调,我们需要还可以转弯。此时就需要使用turtle的转向方法,左转为left,右转为right,如下我们在前述代码基础上增加左转方法,并设定角度为90度,然后继续往前100步。

import turtle
turtle.forward(100)
turtle.backward(50)
turtle.left(90)
turtle.forward(100)

运行程序后,画布上画笔先是笔头左转了90度方向,变成了向上,然后沿着向上的方法画出了长度为100像素的一条线,此时图形变成了一个倒丁字形状:

上述代码中left方法与forward方法一样,括号里的参数也可以随意设定,比如将left方法里的90度修改为45度:

import turtle
turtle.forward(100)
turtle.backward(50)
turtle.left(45)
turtle.forward(100)

再运行程序,此时图形就变为一个钝角形状:

由此看来,改变left方法里的角度参数,画笔就可以绘制出不同形状的图形。

与左转left方法使用方法一致,右转right方法用于向右转,其中right(角度)中的角度参数也可以根据需要来设置。例如在上述左转前行的基础上,设定右转90度,然后前行100步:

import turtle
turtle.forward(100)
turtle.backward(50)
turtle.left(45)
turtle.forward(100)
turtle.right(90)
turtle.forward(100)

运行代码时,绘制图形效果如下:

接下来可以思考一下,如果在上述基础上将右侧下部开口的三角形状进行封闭,也就是形成一个完整的三角形呢?

很显然,此时需要动脑筋稍微计算一下。首先箭头需要右转135度,然后再前行100步:

import turtle
turtle.forward(100)
turtle.backward(50)
turtle.left(45)
turtle.forward(100)
turtle.right(90)
turtle.forward(100)
turtle.right(135)
turtle.forward(100)

再次运行程序,画笔先在原有位置顺时针方向旋转135度,笔头方向正好朝西,然后开始画一个长为100像素的直线,就得到一个右侧封闭的三角形,如下:

到这里我们小结一下,使用turtle绘图的基本动作方法包括:forward(前进参数)、backward(后退参数)、left(左转角度)、right(右转角度)。turtle是乌龟绘图模块名,该模块中内置了这些动作方法,因此在使用的时候直接调用并给定相应参数即可。简单理解,turtle就是那支画笔,这些基本动作方法就用于控制画笔的画画方式。用python的面向对象概念来理解,这些方法属于turtle这个绘图对象,调用时使用了“.”运算符,其格式为turtle.方法名(参数)。turtle这个绘图对象还有很多类似方法,使用格式均为turtle.方法名(参数)。

(2)设置画布和画笔颜色

试想我们是否可以设置一下画布和画笔的颜色呢?肯定是可以的,调用画笔的bgcolor方法就可以设置画布背景颜色,格式为:turtle.bgcolor(颜色参数);调用其color方法就可以设置画笔颜色,格式为turtle.color(颜色参数)。这里的颜色参数直接给常见的颜色,如red、white、yellow、purple,使用的时候加单引号;也可以给RGB颜色代码,如255,255,255为白色,0,0,0为黑色。需要说明的是,设置画布背景颜色一般会放置在程序开始部分,而画笔颜色可以在需要的地方设置即可。如将上述绘制三角形的代码修改一下,增加画布背景和画笔颜色:

import turtle
turtle.bgcolor('black')
turtle.color('yellow')
turtle.forward(100)
turtle.backward(50)
turtle.left(45)
turtle.color('white')
turtle.forward(100)
turtle.right(90)
turtle.forward(100)
turtle.color('red')
turtle.right(135)
turtle.forward(100)

运行代码,此时画布变为了黑色,画笔先为黄色,然后为白色,最后为红色,效果如下:

上面我们通过控制turtle画笔的动作和转向角度,画出了一个三角形。想想心里是不是已经有了小小的成就感了?看来用turtle软件画画还是比较简单的。

(3)for循环语句控制重复动作

下面我们来在画布上画一个正方形。如何设计呢?首先来分析一下,我们知道正方形每条边长度相同,边与边的夹角为90度。因此可以先往前移动一个距离d,然后左转90度,转向后继续往前移动距离d,再左转90度,继续移动距离d,再来一次左转90度,移动距离d,这样起点和终点就重合了,也就画出了一个完整的正方形。我们来看代码:

import turtle
turtle.bgcolor('black')
turtle.color('yellow')
turtle.forward(100)
turtle.left(90)
turtle.forward(100)
turtle.left(90)
turtle.forward(100)
turtle.left(90)
turtle.forward(100)
turtle.left(90)

执行后,画笔就在画布上画出了一个正方形:

仔细观察代码,可以发现如果把turtle.forward(100)、turtle.left(90)这两行语句作为一个动作组合的话,整个代码中一共重复了四次,这种重复动作写在代码中还是有点冗长的,试想如果重复100次这个组合动作,那就得将这个组合动作代码重复编写100次,这样做肯定不科学。如何简化这种重复执行动作组合呢?python中提供了控制循环的for语句,专门用于解决这类重复性问题。我们先来修改一下画正方形的代码:

import turtle
turtle.bgcolor('black')
turtle.color('yellow')
totalTimes=4                       #设定一共需要重复的次数
for times in range(totalTimes):    #使用for语句对每一次进行设计相同的动作组合
    turtle.forward(100)            #设定前移100个像素点
    turtle.left(90)                #然后左转90度

执行后效果与上述图是一样的。这里代码就简化多了,代码中for语句就用于设计循环语句,其使用方法为:

for times in range(totalTimes): 
    #这里写需要重复的代码块。

上述画四边形时,相同动作组合重复了4次,动作组合中转向角度为90度,两个数字相乘正好为360度,从角度来说就是从起始点出发旋转一周回到原点,也恰好构成一个封闭的图形。如果还想画一个封闭的五边形,就可以设计动作组合中转向角度为72度,重复次数为5次;如果画一个封闭的六边形,设计转向角度为60度,重复次数为6次即可。如下设计在画布上先画五边形,然后画六边形的代码:

import turtle
turtle.bgcolor('black')
turtle.color('yellow')
#先画6边形
totalTimes=6
for times in range(totalTimes):
    turtle.forward(100)
    turtle.left(60)
#然后左转向150度,并往前移动50个像素点
turtle.left(150)
turtle.forward(50)
#最后画5边形
totalTimes=5
for times in range(totalTimes):
    turtle.forward(100)
    turtle.left(72)

执行上述代码,在画布上画出的效果是这样的:

这样是不是就可以画一个圆呢?只要将画笔移动的距离设置短一些,如设置为2,转向设置也为2,那重复次数就必须设置为180,由此就可以画出一个妥妥的圆了。代码如下:

import turtle
turtle.bgcolor('black')
turtle.color('yellow')
totalTimes=180
for times in range(totalTimes):
    turtle.forward(2)
    turtle.left(2)

执行后效果如下:

不过在turtle软件中已经内置好了画圆的方法,就是使用turtle.circle(半径参数),给定半径参数就能完成圆的绘制。如下代码:

import turtle
turtle.bgcolor('black')
turtle.color('yellow')
#画一个半径为100的圆
turtle.circle(100)     

(4)设置坐标和画笔位置

到现在为止,我们已经掌握了画基本图形的方法。不过仔细观察的话也可以发现每次画画时画笔总是从画布的中心出发,因为这是turtle模块设置好了的,默认从中心点出发。如果使用二维坐标来表示的话,画布的中心位置坐标为(0,0),即纵横坐标均为0。我们也可以使用turtle模块的setpos方法修改其位置,如turtle.setpos(10,10)就是设置画笔纵坐标为10,横坐标也为10;如若设置为turtle.setpos(10,10),就是设置画笔横坐标为10,也就是中心点往右10个像素点,然后再往上10个像素点。如果用数学角度来说明的话,新的起始点就在中心点右偏上45度,距离为d=(10* 10+10* 10)的平方根。

我们来试一下:

import turtle
turtle.bgcolor('black')
turtle.color('yellow')
#画笔默认在画布的中心位置,坐标为(0,0)
#设置画笔的位置挪到纵横坐标均为10像素的位置,即中心点往右45度方向
turtle.setpos(10,10)
#开始画圆,画一个半径为100像素的圆
turtle.circle(100)

运行程序后,画笔先从中心位置挪到指定位置(10,10),然后开始画圆,效果图如下:

这个圆画的不漂亮,起始点貌似有个尾巴,这是画笔最开始从中心位置挪到设定位置时画笔移动的痕迹。如何去除这个痕迹呢?我们可以这样做:使用turtle提供的提笔方法penup( ),也就是先从中心点将画笔提起来,画笔在空中挪至设定位置,然后到了设定位置再将画笔落到画布上,此时就使用落笔方法turtle.pendown( ),这样我们修改上述代码如下:

import turtle
turtle.bgcolor('black')
turtle.color('yellow')
#提起画笔
turtle.penup()
#设置画笔的位置挪到纵横坐标均为10像素的位置,即中心点往右45度方向
turtle.setpos(10,10)
#落下画笔
turtle.pendown()
#开始画圆,画一个半径为100像素的圆
turtle.circle(30)

再来执行代码,那个多余的尾巴就没有了。同时如果想画图结束时那个画笔不显示,可以使用hideturtle方法,即隐藏画笔。由此可以得到启发,使用提笔落笔的方法我们就可以在同一个画布上画出很多图形,当然前提是需要计算好位置。由此设计的时候可以先用笔参考如下坐标图给定位置:

例如我们来画个笑脸试试。

import turtle
turtle.bgcolor('black')
turtle.color('yellow')
#先画笑脸轮廓,画一个半径为100像素的圆
turtle.circle(100)
#提笔到左上角(-40,120)位置,画一个小圆,表示右眼
turtle.penup()
turtle.setpos(-40,120)
turtle.pendown()
turtle.circle(10)
#提笔到中部位置,先画一条短线表示上嘴唇
turtle.penup()
turtle.setpos(-10,60)
turtle.pendown()
turtle.forward(20)
#继续下移一定距离,画一条短弧线表示下嘴唇
turtle.penup()
turtle.setpos(-10,40)
turtle.pendown()
totalTimes=4
for times in range(totalTimes):
    turtle.forward(5)
    turtle.left(10)
#提笔到右上角(40,120)位置,画一个小圆,表示右眼
turtle.penup()
turtle.setpos(40,120)
turtle.pendown()
turtle.circle(10)
#隐藏那个画笔箭头
turtle.hideturtle()

运行效果如下图:

实话实说美观程度一般,不过至少画出了一个小人的脸,好像不咋笑。我们使用了turtle.penup()方法,就是提笔,而turtle模块中本身就自带了pen方法,也就是画笔方法,可以通过pen方法来设置画笔的尺寸、颜色,也可以直接使用pencolor、pensize等方法。具体使用格式为:

turtle.pen(pensize=10,pencolor='red',fillcolor='yellow')

或者直接设定:

turtle.pencolor('red')
turtle.pensize(10)

如果需要填充颜色,就需要使用turtle的beginfill()和end_fill() 组合,格式为:

turtle.fillcolor("yellow")
turtle.begin_fill()
turtle.circle(100)
turtle.end_fill()

我们将这些颜色的设定加入之前画的那个笑脸代码中:

import turtle
turtle.bgcolor('black')
turtle.color('yellow')
#先画笑脸轮廓,画一个半径为100像素的圆
turtle.fillcolor("yellow")
turtle.begin_fill()
turtle.circle(100)
turtle.end_fill()
#提笔到左上角(-40,120)位置,画一个小圆,表示右眼
turtle.pen(pensize=10,pencolor='red',fillcolor='yellow')
turtle.penup()
turtle.setpos(-40,120)
turtle.pendown()
turtle.circle(10)
#提笔到中部位置,先画一条短线表示上嘴唇
turtle.penup()
turtle.setpos(-10,60)
turtle.pendown()
turtle.forward(20)
#继续下移一定距离,画一条短弧线表示下嘴唇
turtle.penup()
turtle.setpos(-10,40)
turtle.pendown()
totalTimes=4
for times in range(totalTimes):
    turtle.forward(5)
    turtle.left(10)
#提笔到右上角(40,120)位置,画一个小圆,表示右眼
turtle.pen(pensize=10,pencolor='red',fillcolor='yellow')
turtle.penup()
turtle.setpos(40,120)
turtle.pendown()
turtle.circle(10)
#隐藏那个画笔箭头
turtle.hideturtle()

再运行代码,就得到效果图如下:

我们来画一个小车,在画的时候先需要在纸上稍微设计一下车的基本结构参数,如长度和高度等等。示例代码如下:

import turtle
turtle.bgcolor('black')
turtle.color('yellow')
#先画后轮子
turtle.fillcolor("yellow")
turtle.begin_fill()
turtle.circle(20)
turtle.end_fill()
#提笔往前挪,画前轮
turtle.penup()
turtle.forward(200)
turtle.pendown()
turtle.begin_fill()
turtle.circle(20)
turtle.end_fill()
#画车轮廓
turtle.left(90)
turtle.forward(50)
turtle.right(90)
turtle.forward(70)
turtle.left(135)
turtle.forward(60)
turtle.right(45)
turtle.forward(2)
turtle.left(90)
turtle.forward(70)
turtle.right(90)
turtle.forward(20)
turtle.left(90)
turtle.forward(160)
turtle.left(50)
turtle.forward(60)
turtle.left(40)
turtle.forward(18)
turtle.left(90)
turtle.forward(240)
#画后轮与车轮廓接触线
turtle.penup()
turtle.home()
turtle.pendown()
turtle.left(90)
turtle.forward(50)
turtle.write("this car is made by Mr.cao,2019")
#车上方写标题
turtle.penup()
turtle.setpos(60,140)
turtle.pendown()
turtle.write("豪车!",font=("Times", 18, "bold"))
#隐藏那个画笔箭头
turtle.hideturtle()

运行效果如图:

(5)使用函数

还想画别的吗?只要有足够的想象力,大部分的图都可以使用这个turtle来实现。那我们在画的过程中每完成一个图形,是否可以将这个画图形的过程包装起来给个名字,如果想画这个图形,直接调用它的名字就可以呢。肯定是可以的,而且还非常方便。python中的函数就是用来做这个事情的,其基本格式为:

def 函数名称(参数):
    #执行代码

如果以画画为例,函数名称就可以命名为画图形名称,这里的参数是可选项,在画画过程中如果想采用不同颜色的笔,就可以将笔的颜色作为一个参数变量,每次使用这个函数时给定笔的颜色参数,就可以按照自己喜欢的颜色画画了。也可以将别的可以变化的参数作为变量参数来设定。执行代码处就是代码块,用于完成整个图形绘制的过程。举个栗子,我们将前面画四边形、五边形、六边形等可以包装成一个函数,名称取为drawShape,参数包括两个,一个是totalTimes,总的边数,一个是distance,就是画画长度,代码如下:

def drawShape(totalTimes,distance):         
    for time in range(totalTimes):
        turtle.forward(distance)
        turtle.left(360/totalTimes)

这样我们想画这种类似形状的时候,只需要调用这个函数名,给定两个参数的值,就可以了。例如:

import turtle
turtle.bgcolor('black')
turtle.color('yellow')
#编写一个函数drawShape,用于画多边形
def drawShape(totalTimes,distance):         
    for time in range(totalTimes):
        turtle.forward(distance)
        turtle.left(360/totalTimes)
#调用这个函数,来画一个五边形,每边长度为80个像素
drawShape(5,80)

(6)turtle时钟和事件响应

在turtle中还有动作触发响应事件,也就是通过鼠标或键盘来控制画画开始或结束,还可以设置时钟,这样我们就可以画点动画了,当然是较为简单的。例如我们将上述画笑脸和画车两个作品放在一个文件里,先画笑脸,等待2秒后,再画出车来,代码参考如下:

import turtle
turtle.bgcolor('black')
#定义一个画车的函数
def drawCar():
    turtle.color('yellow')
    #先画后轮子
    turtle.fillcolor("yellow")
    turtle.begin_fill()
    turtle.circle(20)
    turtle.end_fill()
    #提笔往前挪,画前轮
    turtle.penup()
    turtle.forward(200)
    turtle.pendown()
    turtle.begin_fill()
    turtle.circle(20)
    turtle.end_fill()
    #画车轮廓
    turtle.left(90)
    turtle.forward(50)
    turtle.right(90)
    turtle.forward(70)
    turtle.left(135)
    turtle.forward(60)
    turtle.right(45)
    turtle.forward(2)
    turtle.left(90)
    turtle.forward(70)
    turtle.right(90)
    turtle.forward(20)
    turtle.left(90)
    turtle.forward(160)
    turtle.left(50)
    turtle.forward(60)
    turtle.left(40)
    turtle.forward(18)
    turtle.left(90)
    turtle.forward(240)
    #画后轮与车轮廓接触线
    turtle.penup()
    turtle.home()
    turtle.pendown()
    turtle.left(90)
    turtle.forward(50)
    turtle.write("this car is made by Mr.cao,2019")
    #车上方写标题
    turtle.penup()
    turtle.setpos(60,140)
    turtle.pendown()
    turtle.write("豪车!",font=("Times", 22, "bold"))
    #隐藏那个画笔箭头
    turtle.hideturtle()
#定义个画笑脸的函数
def drawFace():
    turtle.color('yellow')    
    turtle.speed(0.1)
    #先画笑脸轮廓,画一个半径为100像素的圆
    turtle.circle(100)
    #提笔到左上角(-40,120)位置,画一个小圆,表示右眼
    turtle.penup()
    turtle.setpos(-40,120)
    turtle.pendown()
    turtle.circle(10)
    #提笔到中部位置,先画一条短线表示上嘴唇
    turtle.penup()
    turtle.setpos(-10,60)
    turtle.pendown()
    turtle.forward(20)
    #继续下移一定距离,画一条短弧线表示下嘴唇
    turtle.penup()
    turtle.setpos(-10,40)
    turtle.pendown()
    totalTimes=4
    for times in range(totalTimes):
        turtle.forward(5)
        turtle.left(10)
    #提笔到右上角(40,120)位置,画一个小圆,表示右眼
    turtle.penup()
    turtle.setpos(40,120)
    turtle.pendown()
    turtle.circle(10)
    turtle.penup()
    turtle.setpos(-80,-30)
    turtle.pendown()
    turtle.write("等待2秒中,准备带你去看豪车了哦!",font=32)
    #隐藏那个画笔箭头