Python标准库程序框架——turtle海龟绘图

Python标准库程序框架——turtle海龟绘图


​ 我想,科普最好的对象是小朋友,那么就写一下被移植到Python标准库里的turtle库吧。以下代码基于Python 3.8.1。

概述

​ 海龟绘图,最初来自于 Wally Feurzeig, Seymour Papert 和 Cynthia Solomon 于 1967 年所专门为引导儿童学习编程创造的 Logo 编程语言。turtle库的实现过程很形象,犹如一只海龟在画布上画画。海龟绘图很适合用来培养小朋友对编程的学习兴趣。

​ 试想象一下,在一块画布上,起始位置在x-y平面的(0,0)点,执行```import turtle``来召唤一只拿着画笔的海龟(也就是一个点),再利用turtle库里一系列的指令(方法)来指挥这只海龟来爬。最后通过组合这些指令,海龟爬行的轨迹将可以轻松地绘制出精美的形状和图案。并且通过对应函数,能按我们的要求把海龟的轨迹在显示设备上输出显示。

​ 目前的turtle模块是基于Python标准发行版2.5重新编写和扩展,并与原模块100%兼容。因此能以交互方式使用模块的所有命令、类和方法。

​ turtle模块提供面向对象和面向过程两种形式的海龟绘图基本组件。具体如下:

面向对象:

  • TurtleScreen 类定义图形窗口作为绘图海龟的运动场。它的构造器需要一个 tkinter.CanvasScrolledCanvas 作为参数。应在 turtle 作为某个程序的一部分的时候使用。
  • Screen() 函数返回一个 TurtleScreen 子类的单例对象。此函数应在 turtle 作为独立绘图工具时使用。作为一个单例对象,其所属的类是不可被继承的。

TurtleScreen/Screen的所有方法还存在对应的函数,即作为面向过程的接口组成部分。

  • RawTurtle 类定义海龟对象在TurtleScreen上绘图。它的构造器需要一个 Canvas, ScrolledCanvasTurtleScreen作为参数,以指定 RawTurtle对象在哪里绘图。

  • RawTurtle派生出子类Turtle,该类对象在Screen实例上绘图,若实例不存在则会自动创建。

RawTurtle/Turtle 的所有方法也存在对应的函数,即作为面向过程的接口组成部分

面向过程:

​ 过程式接口提供与ScreenTurtle类的方法相对应的函数。函数名与对应的方法名相同。当Screen类的方法对应函数被调用时会自动创建一个Screen 对象。当Turtle类的方法对应函数被调用时会自动创建一个 (匿名的)Turtle 对象。

​ 当需要屏幕上有多个海龟的时候,就必须使用面向对象的接口。

可用的turtle和Screen方法

​ 如前文所说,我们通过import turtle召唤了一只拿着画笔的海龟,海龟的的动作以及画笔都是通过方法来控制的。同时,作为一只被召唤出来的二维生物,我们作为比他高维的生物,自然有很多降维操纵甚至打击的方法。从某种角度上来说,我们对这些turtle有近乎神迹般的操纵和控制。 然而并不是。具体方法如下。

RawTurtle/Turtle方法和对应函数

以下都是使用Turtle类的实例,命名为turtle

  1. 海龟动作

    ​ 我们能控制海龟的前进后退,左转右转,爬行速度,甚至能让海龟像赛亚人或者哈利波特里的巫师一样学会幻影移行,同时能随时获知海龟的位置信息。

    1. 移动和绘制

      forward(distance) :前进distance距离

      >>> turtle.position()
      (0.00,0.00)
      >>> turtle.forward(distance)
      >>> turtle.position()
      (distance,0.00)
      >>> turtle.forward(distance)
      >>> turtle.position()
      (distance+distance,0.00)
      

      backward(distance) :后退distance距离

      >>> turtle.position()
      (0.00,0.00)
      >>> turtle.backward(distance)
      >>> turtle.position()
      (-distance,0.00)
      

      right(angle) :右转angle个单位

      >>> turtle.heading()
      22.0
      >>> turtle.right(angle)
      >>> turtle.heading()
      22.0-angle+360.0
      

      left(angle):左转angle个单位

      >>> turtle.heading()
      22.0
      >>> turtle.left(angle)
      >>> turtle.heading()
      22.0+angle
      

      goto(x,y=None) | setposition(x,y=None) :前往/定位一个绝对坐标
      setx(x) 设置x坐标
      sety(y) 设置y坐标
      setheading(to_angle) 设置朝向

      import turtle
      from turtle import *
      color('red', 'yellow')
      turtle.setheading(90)
      turtle.heading()
      done()
      

      home() 返回原点
      circle(radius, extent=None, steps=None) 画圆

      import turtle
      from turtle import *
      color('red', 'yellow')
      turtle.home()
      turtle.position()
      turtle.heading()
      turtle.circle(50)
      turtle.position()
      turtle.heading()
      turtle.circle(120, 180)  # draw a semicircle
      turtle.position()
      turtle.heading()
      done()
      

      dot(size=None, color) 画点
      stamp() 印章
      clearstamp(stampid) 清除印章
      clearstamps(n=None) 清除多个印章
      undo() :撤消海龟最近一个或多个动作
      speed(speed=None) :控制海龟移动速度

    2. 获取海龟的状态

      position() | pos() 位置:返回海龟当前的坐标
      towards() :返回海龟朝向
      xcor() :返回海龟x坐标
      ycor() :返回海龟y坐标
      distance() 返回从海龟位置到另一位置的距离

  2. 画笔控制

    ​ 同时,海龟对于我们来说只是用来画画的工具龟,所以我们对于它用来画轨迹的画笔也有相应的方法来控制。

    1. 绘图状态
      pendown() 画笔落下:海龟移动时将画线
      penup() 画笔抬起:海龟移动时不画线
      pensize(width=None) 画笔粗细
      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": 数值

      isdown() 画笔是否落下:判断画笔是否落下,落下返回True,抬起返回False

    2. 颜色控制
      pencolor(*args) :返回和设置画笔颜色

    允许四种不同的输入格式:

    • pencolor():返回以颜色描述字符串或元组表示的当前画笔颜色;
    • pencolor(colorstring):设置画笔颜色为colorstring指定的Tk颜色描述字符串;
    • pencolor((r,g,b)):设置画笔颜色为以r,g,b元组表示的RGB颜色;
    • pencolor(r,g,b):设置画笔颜色为以r,g,b表示的RGB颜色;

    fillcolor(*args) :返回和设置填充颜色

    同pencolor(*args)一样,有四种不同的输入格式:

    • fillcolor():返回以颜色描述字符串或元组表示的当前填充颜色;
    • fillcolor(colorstring):设置填充颜色为colorstring指定的Tk颜色描述字符串;
    • fillcolor((r,g,b)):设置填充颜色为以r,g,b元组表示的RGB颜色;
    • fillcolor(r,g,b):设置填充颜色为以r,g,b表示的RGB颜色;

    color(* args) 返回或设置画笔颜色和填充颜色

    color()允许多种输入格式:

    • color():返回以一对颜色描述字符串或元组表示的当前画笔颜色和填充颜色;
    • 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),rbg格式也与值类似;
    1. 填充
      filling() 是否填充
      begin_fill() 开始填充
      end_fill() 结束填充

    2. 更多绘图控制
      reset() 重置:从屏幕中删除海龟的绘图,同时海龟返回原点并重置所有变量为默认值
      clear() 清空:从屏幕中只删除海龟的绘图
      write(*arg, move=False, align="left", font=("Arial",8,"normal")) :书写文本

      write()的参数具体为:

      arg -- 要书写到TurtleScreen的对象'

      move -- True/False

      align -- 字符串"left","center"或"right"

      font -- 一个三元组(fontname, fontsize, fonttype)

  3. 海龟状态

    1. 可见性
      showturtle() 显示海龟
      hideturtle() 隐藏海龟:隐藏海龟可显著加快绘制速度
      isvisible() 检查是否可见

    2. 外观
      shape(name=None)

      设置海龟形状为name指定的形状名,如未指定形状名则返回当前的形状名

      resizemode(rmode=None) :大小调整模式

      rmode为以下值之一:"auto","user","noresize";

      不同的大小调整模式有不同的效果如下:

      auto: 根据画笔的粗细值调整海龟外观;

      user: 根据拉伸因子和轮廓宽度值调整海龟的外观,两者通过shapesize()设置,user模式会在shapesize()带参数调用时生效;

      noresize:不调整海龟的外观大小;

      shapesize(stretch_wid=None, strech_len=None, outline=None) 形状大小
      shearfactor(shear=None) 剪切因子
      tiltangle(angle=None) :设置或返回当前的倾角
      tilt(angle) :海龟形状自其当前倾角转动angle的角度
      shapetransform(t11=None, t12=None, t21=None, t22=None) :设置或返回海龟形状的当前变形矩阵
      get_shapepoly() 获取形状多边形

  4. 使用事件

    onclick(fun, btn=1, add=None)

    当鼠标点击,触发事件fun函数并传入两个参数表示在画布上点击的坐标,

    fun -- 函数,调用时传入两个参数, 以表示在画布上点击的坐标;

    btn -- 鼠标按钮编号,默认值为1,即鼠标左键;

    add -- True或False, 为False将取代先前的绑定

    onrelease(fun, btn=1,add=None) 当鼠标释放

    当鼠标按键释放,触发事件,三个参数同onclick()

    ondrag(fun, btn=1,add=None) 当鼠标拖动

    当鼠标移动,触发事件,三个参数同上

  5. 特殊海龟方法

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

TurtleScreen/Screen方法及对应函数*

  1. 窗口控制

    bgcolor(*args) :设置或返回背景颜色
    bgpic(picname=None) 设置背景图片或返回当前背景图片名称

    picname可以为字符串(若为文件名,则将相应图片设为背景),nopic(删除当前背景图片),None(返回当前背景图片文件名)

    clear() | clearscreen() 清屏
    reset() | resetscreen() 重置
    screensize(canvwidth=None, canvheight=None, bg=None) 屏幕大小

    canviwidth -- 以像素表示画布的新宽度值

    canvheight -- 以像素表示画面的新高度值

    bg -- 以颜色字符串或颜色元组表示的新背景颜色

    setworldcoordinates(llx, lly, urx, ury) 设置世界坐标系

  2. 动画控制

    delay() 延迟
    tracer(n=None, delay=None)

    启用/禁用海龟动画并设置刷新图形的延迟时间

    update() :执行一次TurtleScreen刷新

  3. 使用屏幕事件

    listen(xdummy=None, ydummy=None) :

    设置焦点到TurtleScreen, 以接收按键事件

    onkey(fun, key)

    绑定指定fun函数到按键释放事件

    onkeypress(fun, key)

    绑定指定fun函数到指定按键的按下事件

    onclick(fun, btn=1, add=None)

    绑定指定fun函数到指定按键的点击屏幕事件

    ontimer(fun, t=0)

    安装一个计时器,在t毫秒后,调用指定fun函数

    mainloop() | done() 主循环

    调用Tkinter的mainloop函数

  4. 输入方法

    textinput(title, prompt) 文本输入

    弹出一个对话框窗口用来输入一个字符串。
    title -- 对话框窗口的标题
    prompt -- 一条用来描述要输入的信息的文本

    numinput(title, prompt, default=None, minval=None, maxval=Non) 数字输入

    弹出一个对话框窗口用来输入一个数值。
    title -- 对话框窗口的标题
    prompt -- 一条用来描述要输入的数值信息的文本
    default -- 默认值
    minval -- 可输入的最小值
    maxval -- 可输入的最大值

  5. Screen 专有方法

    bye()

    关闭海龟绘图窗口

    exitonclick()

    将bye()方法绑定到Screen上的鼠标事件

    setup(width=CFG["width"], height= CFG["height"],startx=CFG["leftright"],starty=_CFG["topbottom"])

    设置主窗口的大小和位置。

    width -- 数值为整形则表示大小的像素值,若为浮点数则表示屏幕的占比,默认为屏幕50%

    height -- 数值为整形表示高度的像素值,若为浮点数则表示屏幕的占比,,默认为屏幕75%

    startx -- 正值表示初始位置距离屏幕左边缘像素值,负值表示距离右边缘,None表示窗口水平居中

    starty -- 正值表示初始位置距离屏幕上边缘多少像素,负值表示距离下边缘,None表示窗口垂直居中

    title(titlestring)

    设置海龟窗口标题为title string指定的文本

结语

​ 本想着写一篇面向儿童的科普文。写着写着,被Python官方的手册带偏了,权当是给教儿童科普编程的人小小的对turtle方法的归类和介绍吧。

​ python是一门简约但不简单的语言,在python的编译器中输入import this执行后出来的《Python之禅》中,从Python准则的诗句中,可见一斑。Python是一样工具,更是一门语言,它应该很有趣。而通常有趣到极致的代名词是儿童。同时,一门语言想要延续,就应当能吸引年轻的血液。而Python标准库下的turtle模块,应该就是实现这两种功能的法宝之一。

​ 一九九几年和两千零几年说的信息化,再过几天就是2020年,离2000年也已过二十年,现在讨论的和追捧的也已经是智能化。离1946年2月14日也就快74年时间。二十年时间超过了计算机寿命的四分之一,而计算机家用早已推广,还捧出来一个世界首富。可是,对于应用计算机最为核心的编程,到目前还有很多人不掌握。苹果ceo库克拜访上海某小学推广swift语言和社交媒体提到某个学编程的儿童成为了新闻,这种事情个人认为是不正常的。

​ 套用某部电影说的话”21世纪最缺的是人才“。虽然最不缺和不值钱的貌似也是人才。人才从哪里来?人才是从小培养的。而如果有那么一种编程语言,能让小朋友都能学会,并且通过这个语言以后能更容易学习更多其他的语言,无疑是非常好的。对于儿童能学习知识,也能方便生活。对于社会,如果这种语言是如swift一样有盈利公司开发的,公司能赚小朋友父母钱;如果这种语言是开源的,那么整个社会的编程水平总会提高那么一丢丢,这就简直是造福全世界了。

​ 最后,附上一个搜集资料(https://www.cnblogs.com/yangbin1212/p/9763936.html)时看到的使用turtle画出来的有趣的《小猪佩奇》python源代码吧。

​ 完成效果图如下:

"""
@time :12/30/2019
@author: menkwan
"""
# coding:utf-8
import turtle as t
# 绘制小猪佩奇
# =======================================
t.pensize(4)
t.hideturtle()
t.colormode(255)
t.color((255, 155, 192), "pink")
t.setup(840, 500)
t.speed(10)

# 鼻子
t.penup()
t.goto(-100,100)
t.pendown()
t.seth(-30)
t.begin_fill()
a = 0.4
for i in range(120):
    if 0 <= i < 30 or 60 <= i < 90:
        a = a+0.08
        t.left(3)  # 向左转3度
        t.forward(a)  # 向前走a的步长
    else:
        a = a-0.08
        t.left(3)
        t.forward(a)
        t.end_fill()

t.penup()
t.seth(90)
t.forward(25)
t.seth(0)
t.forward(10)
t.pendown()
t.pencolor(255, 155, 192)
t.seth(10)
t.begin_fill()
t.circle(5)
t.color(160, 82, 45)
t.end_fill()

t.penup()
t.seth(0)
t.forward(20)
t.pendown()
t.pencolor(255, 155, 192)
t.seth(10)
t.begin_fill()
t.circle(5)
t.color(160, 82, 45)
t.end_fill()

# 头
t.color((255, 155, 192), "pink")
t.penup()
t.seth(90)
t.forward(41)
t.seth(0)
t.forward(0)
t.pendown()
t.begin_fill()
t.seth(180)
t.circle(300, -30)
t.circle(100, -60)
t.circle(80, -100)
t.circle(150, -20)
t.circle(60, -95)
t.seth(161)
t.circle(-300, 15)
t.penup()
t.goto(-100, 100)
t.pendown()
t.seth(-30)
a = 0.4
for i in range(60):
    if 0 <= i < 30 or 60 <= i <90:
        a = a+0.08
        t.left(3)  # 向左转3度
        t.forward(a)  # 向前走a的步长
    else:
        a = a-0.08
        t.left(3)
        t.forward(a)
        t.end_fill()

# 耳朵
t.color((255, 155, 192), "pink")
t.penup()
t.seth(90)
t.forward(-7)
t.seth(0)
t.forward(70)
t.pendown()
t.begin_fill()
t.seth(100)
t.circle(-50, 50)
t.circle(-10, 120)
t.circle(-50, 54)
t.end_fill()

t.penup()
t.seth(90)
t.forward(-12)
t.seth(0)
t.forward(30)
t.pendown()
t.begin_fill()
t.seth(100)
t.circle(-50, 50)
t.circle(-10, 120)
t.circle(-50, 56)
t.end_fill()

#眼睛
t.color((255, 155, 192), "white")
t.penup()
t.seth(90)
t.forward(-20)
t.seth(0)
t.forward(-95)
t.pendown()
t.begin_fill()
t.circle(15)
t.end_fill()

t.color("black")
t.penup()
t.seth(90)
t.forward(12)
t.seth(0)
t.forward(-3)
t.pendown()
t.begin_fill()
t.circle(3)
t.end_fill()

t.color((255, 155, 192), "white")
t.penup()
t.seth(90)
t.forward(-25)
t.seth(0)
t.forward(40)
t.pendown()
t.begin_fill()
t.circle(15)
t.end_fill()

t.color("black")
t.penup()
t.seth(90)
t.forward(12)
t.seth(0)
t.forward(-3)
t.pendown()
t.begin_fill()
t.circle(3)
t.end_fill()

# 腮
t.color((255, 155, 192))
t.penup()
t.seth(90)
t.forward(-95)
t.seth(0)
t.forward(65)
t.pendown()
t.begin_fill()
t.circle(30)
t.end_fill()

# 嘴
t.color(239, 69, 19)
t.penup()
t.seth(90)
t.forward(15)
t.seth(0)
t.forward(-100)
t.pendown()
t.seth(-80)
t.circle(30, 40)
t.circle(40, 80)

# 身体
t.color("red", (255, 99, 71))
t.penup()
t.seth(90)
t.forward(-20)
t.seth(0)
t.forward(-78)
t.pendown()
t.begin_fill()
t.seth(-130)
t.circle(100,10)
t.circle(300,30)
t.seth(0)
t.forward(230)
t.seth(90)
t.circle(300,30)
t.circle(100,3)
t.color((255,155,192),(255,100,100))
t.seth(-135)
t.circle(-80,63)
t.circle(-150,24)
t.end_fill()

# 手
t.color((255,155,192))
t.penup()
t.seth(90)
t.forward(-40)
t.seth(0)
t.forward(-27)
t.pendown()
t.seth(-160)
t.circle(300,15)
t.penup()
t.seth(90)
t.forward(15)
t.seth(0)
t.forward(0)
t.pendown()
t.seth(-10)
t.circle(-20,90)

t.penup()
t.seth(90)
t.forward(30)
t.seth(0)
t.forward(237)
t.pendown()
t.seth(-20)
t.circle(-300,15)
t.penup()
t.seth(90)
t.forward(20)
t.seth(0)
t.forward(0)
t.pendown()
t.seth(-170)
t.circle(20,90)

# 脚
t.pensize(10)
t.color((240,128,128))
t.penup()
t.seth(90)
t.forward(-75)
t.seth(0)
t.forward(-180)
t.pendown()
t.seth(-90)
t.forward(40)
t.seth(-180)
t.color("black")
t.pensize(15)
t.forward(20)

t.pensize(10)
t.color((240, 128, 128))
t.penup()
t.seth(90)
t.forward(40)
t.seth(0)
t.forward(90)
t.pendown()
t.seth(-90)
t.forward(40)
t.seth(-180)
t.color("black")
t.pensize(15)
t.forward(20)

# 尾巴
t.pensize(4)
t.color((255, 155, 192))
t.penup()
t.seth(90)
t.forward(70)
t.seth(0)
t.forward(95)
t.pendown()
t.seth(0)
t.circle(70, 20)
t.circle(10, 330)
t.circle(70, 30)
t.done()

你可能感兴趣的:(Python标准库程序框架——turtle海龟绘图)