Python——turtle库

前言:海龟绘图的起源与Python Turtle库的哲学

在计算机图形学的浩瀚世界中,Python的turtle(海龟绘图)库以其独特的魅力,为初学者打开了一扇通往可视化编程的奇妙大门。然而,其深度远不止于简单的入门,它蕴含着事件驱动、状态机、坐标几何以及与底层GUI库(Tkinter)交互的精妙机制。本指南将带您从最底层的逻辑开始,逐步向上,全面、无死角地剖析turtle库的每一个细节,揭示其内部运作原理,探索高级应用技巧,并融入大量原创的实战案例,助您成为turtle绘图的真正大师。

1.1 海龟绘图的哲学:从LOGOR到Python的演变

海龟绘图的概念源于20世纪60年代末的LOGO编程语言。LOGO由Seymour Papert和他的团队在麻省理工学院开发,旨在为儿童提供一个直观且富有交互性的学习编程的方式。其核心思想是,通过控制一只“海龟”在屏幕上移动和绘制,来理解程序执行的逻辑。

核心哲学:

  1. 具象化操作:将抽象的编程指令转化为海龟的实际行动(前进、转弯、抬笔、落笔),极大地降低了编程的认知门槛。学习者不需要一开始就理解复杂的坐标系或数学概念,只需想象自己就是那只海龟,一步一步地探索和创造。
  2. 即时反馈:每一次指令的执行,海龟都会立即在屏幕上显示结果,这种即时性为学习者提供了强大的反馈回路,有助于快速发现错误、调整思路并加深理解。
  3. 探索与创造:海龟绘图鼓励通过实验和探索来学习,而不是死记硬背语法。学习者可以自由地组合指令,创造出各种图形和动画,从而培养计算思维和解决问题的能力。
  4. 状态机思想:海龟本身就是一个简单的状态机,它有位置、朝向、笔的状态(抬笔/落笔)、笔的颜色、笔的粗细等一系列内部状态。每一次指令都会改变这些状态,并引发相应的绘图行为。理解这一机制是深入掌握turtle库的关键。

Python的turtle库完美继承并发展了这些哲学,将其融入到Python简洁优雅的语法中。它作为Python标准库的一部分,无需额外安装,使得任何Python用户都能轻松体验海龟绘图的乐趣。

1.2 Python Turtle库:在标准库中的定位与价值

turtle模块是Python标准库中的一个图形模块。这意味着只要您安装了Python,turtle库就已经伴随安装,无需使用pip等工具进行额外安装。这种即开即用的特性,使其成为:

  • 编程入门的理想工具:特别适合教授儿童和编程初学者算法、循环、条件判断等基本编程概念。
  • 可视化工具:可以用于快速绘制简单的几何图形、数学函数曲线、甚至一些简易的数据可视化图表。
  • 动画与游戏原型:虽然不是专业游戏引擎,但其事件处理机制和动画控制能力,足以用来制作简单的交互式动画或小游戏原型,从而理解游戏开发中的基本原理。
  • GUI编程的轻量级入口turtle库底层基于Tkinter,通过学习turtle,可以初步接触到GUI编程的基本思想,如事件循环、控件交互等。

本指南将超越“入门”层面,深入挖掘turtle库的“内部机制”和“高级应用”,让您不仅会用,更能理解其“为什么”和“如何”运作。

第二章:环境准备与核心组件的初步解构

在踏上海龟绘图的旅程之前,我们首先要确保环境的正确搭建,并了解turtle库中几个最核心的组件:绘图屏幕(Screen)和海龟本身(Turtle)。它们是所有绘图操作的基础。

2.1 Python环境的准备与turtle模块的导入

由于turtle是Python标准库的一部分,您只需要确保安装了Python即可。建议使用Python 3.x版本。

导入方式:

有两种主要的方式导入turtle模块,它们各有优缺点,理解其差异对于后续的代码编写至关重要。

  1. import turtle

    • 优点:命名空间清晰,不会与其他模块的名称冲突。
    • 缺点:每次调用turtle函数或类时,都需要加上turtle.前缀。
    • 示例
      import turtle # 导入turtle模块
      
      # 创建屏幕对象
      my_screen = turtle.Screen() # 通过turtle.Screen()来创建屏幕对象
      my_screen.bgcolor("lightblue") # 设置屏幕的背景颜色为浅蓝色
      
      # 创建海龟对象
      my_turtle = turtle.Turtle() # 通过turtle.Turtle()来创建海龟对象
      my_turtle.forward(100) # 让海龟向前移动100个单位
      
      my_screen.mainloop() # 启动事件循环,保持窗口打开
      
      • import turtle: 这一行代码导入了整个 turtle 模块,使得 turtle 模块中定义的所有函数、类和变量都可以通过 turtle. 前缀来访问。
      • my_screen = turtle.Screen(): 创建了一个 Screen 类的实例,并将其赋值给 my_screen 变量。Screen 类代表了绘图窗口。
      • my_screen.bgcolor("lightblue"): 调用 my_screen 对象的 bgcolor 方法,将绘图窗口的背景颜色设置为“浅蓝色”。
      • my_turtle = turtle.Turtle(): 创建了一个 Turtle 类的实例,并将其赋值给 my_turtle 变量。Turtle 类代表了屏幕上的绘图笔,也就是我们通常说的“海龟”。
      • my_turtle.forward(100): 调用 my_turtle 对象的 forward 方法,让海龟向前移动 100 个单位距离。默认情况下,海龟初始方向是向右。
      • my_screen.mainloop(): 这一行非常关键。它启动了 turtle 库内部的事件循环。如果没有这一行,窗口在绘图完成后会立即关闭,您将看不到绘图过程和结果。mainloop 会让程序持续运行,等待用户交互(如点击关闭按钮)。
  2. from turtle import *

    • 优点:可以直接调用turtle中的函数和类,无需前缀,代码看起来更简洁。
    • 缺点:可能导致命名空间污染,如果其他模块也有同名函数或类,可能会产生冲突。
    • 建议:对于简单的、独立的turtle程序,这种方式很方便。但在大型或复杂的项目中,通常不推荐使用*导入。
    • 示例
      from turtle import * # 从turtle模块导入所有内容
      
      # 创建屏幕对象(Screen类本身也被导入了)
      my_screen = Screen() # 可以直接使用Screen()来创建屏幕对象
      my_screen.title("我的第一个海龟程序") # 设置窗口的标题
      
      # 创建海龟对象(Turtle类本身也被导入了)
      my_turtle = Turtle() # 可以直接使用Turtle()来创建海龟对象
      my_turtle.pencolor("red") # 设置海龟的笔颜色为红色
      my_turtle.pensize(3) # 设置海龟的笔宽度为3像素
      
      # 直接调用海龟的移动方法,无需my_turtle.前缀
      # 注意:这里我们仍然使用my_turtle来调用方法,以区分多只海龟或更清晰的面向对象操作。
      # 但如果是单一海龟操作,且没有创建Turtle对象,也可以直接调用如 forward(100)
      # 例如:forward(100) 会默认作用于一个匿名的海龟实例,但这并不是推荐的写法,
      # 因为它使得对多只海龟的控制变得复杂且不直观。
      # 总是显式地创建和控制Turtle对象是最佳实践。
      my_turtle.forward(100) # 海龟向前移动100单位
      my_turtle.right(90) # 海龟向右转90度
      my_turtle.forward(100) # 海龟继续向前移动100单位,形成直角
      
      my_screen.exitonclick() # 点击窗口任意位置即可关闭窗口
      # 或者使用 my_screen.mainloop()
      
      • from turtle import *: 这一行代码将 turtle 模块中的所有公共名称(包括 Screen 类、Turtle 类以及各种绘图函数)直接导入到当前命名空间。这意味着您可以在代码中直接使用 ScreenTurtleforward 等名称,而无需 turtle. 前缀。
      • my_screen = Screen(): 直接使用 Screen() 创建屏幕对象。
      • my_screen.title("我的第一个海龟程序"): 设置窗口标题。
      • my_turtle = Turtle(): 直接使用 Turtle() 创建海龟对象。
      • my_turtle.pencolor("red"): 设置海龟的笔颜色为红色。
      • my_turtle.pensize(3): 设置海龟的笔粗细为 3 像素。
      • my_turtle.forward(100): 让 my_turtle 对象向前移动 100 单位。
      • my_turtle.right(90): 让 my_turtle 对象向右旋转 90 度。
      • my_turtle.forward(100): 再次向前移动 100 单位,与前一步结合形成一个 L 形路径。
      • my_screen.exitonclick(): 这是一个便捷的退出方式。它注册了一个事件监听器,当用户点击绘图窗口时,窗口会自动关闭。这通常比 mainloop() 更适合简单的示例,因为它提供了用户主动结束程序的机制。

本指南的约定:为了保持代码的清晰性和可维护性,本指南将主要采用 import turtle 的导入方式,除非在特定简化场景下为了代码简洁而使用 from turtle import *,届时会特别说明。

2.2 绘图屏幕(Screen)对象的创建与管理

turtle库中的所有绘图操作都发生在一个“屏幕”或“画布”上。这个屏幕由turtle.Screen()类来代表。它是整个绘图环境的管理者,负责窗口的创建、大小、背景、标题、事件处理以及一些全局的绘图设置。

创建Screen对象:

import turtle # 导入turtle模块

# 创建一个屏幕对象
# 通常一个turtle程序只有一个屏幕对象
screen_obj = turtle.Screen() # 创建Screen类的一个实例,这个实例代表了我们的绘图窗口。
  • import turtle: 导入 turtle 模块。
  • screen_obj = turtle.Screen(): 调用 turtle 模块中的 Screen() 构造函数来创建一个新的绘图屏幕窗口对象,并将其引用赋值给 screen_obj 变量。这个对象是所有绘图的基础。

Screen对象的重要方法详解:

2.2.1 窗口尺寸与位置控制:setup()screensize()
  • screen.setup(width=0.5, height=0.75, startx=None, starty=None)

    • 作用:精确控制绘图窗口的大小和在屏幕上的位置。
    • 参数
      • width: 窗口宽度。可以是一个整数(表示像素值),也可以是一个浮点数(表示屏幕宽度的百分比)。默认值为0.5 (屏幕宽度的一半)。
      • height: 窗口高度。同width,可以是像素值或屏幕高度的百分比。默认值为0.75 (屏幕高度的四分之三)。
      • startx: 窗口左上角的X坐标。如果是None,窗口将居中显示。
      • starty: 窗口左上角的Y坐标。如果是None,窗口将居中显示。
    • 示例
      import turtle
      
      my_screen = turtle.Screen() # 创建屏幕对象
      
      # 设置窗口宽度为屏幕宽度的80%,高度为屏幕高度的60%
      my_screen.setup(width=0.8, height=0.6) # 调用setup方法,将窗口宽度设置为屏幕宽度的80%,高度设置为屏幕高度的60%。
      
      # 设置窗口宽度为800像素,高度为600像素
      # my_screen.setup(width=800, height=600)
      
      # 设置窗口宽度为500像素,高度为400像素,并将其左上角放置在屏幕的(100, 50)位置
      # 注意:屏幕坐标系通常是从左上角(0,0)开始,向右X轴正方向,向下Y轴正方向。
      # my_screen.setup(width=500, height=400, startx=100, starty=50)
      
      my_screen.mainloop() # 启动事件循环,等待用户关闭
      
      • my_screen.setup(width=0.8, height=0.6): 这行代码调用 Screen 对象的 setup 方法来配置绘图窗口的尺寸。width=0.8 表示窗口宽度将占整个屏幕宽度的 80%,height=0.6 表示窗口高度将占整个屏幕高度的 60%。默认情况下,窗口会居中显示。
  • screen.screensize(canvwidth=None, canvheight=None, bg=None)

    • 作用:设置画布(绘图区域)的逻辑尺寸,而不是物理窗口的尺寸。当画布尺寸大于窗口尺寸时,会出现滚动条。
    • 参数
      • canvwidth: 画布的逻辑宽度(像素)。
      • canvheight: 画布的逻辑高度(像素)。
      • bg: 画布的背景颜色。
    • 返回值:返回当前的画布宽度、高度和背景颜色(如果未提供参数)。
    • setup()的区别setup()控制的是实际显示出来的窗口大小,screensize()控制的是内部虚拟画布的大小。如果screensize设置的画布远大于setup设置的窗口,那么只有一部分画布内容会显示在窗口中,用户可以通过滚动条查看其他部分(但在turtle中,滚动条不常用)。
    • 示例
      import turtle
      
      my_screen = turtle.Screen() # 创建屏幕对象
      my_screen.setup(width=600, height=400) # 设置窗口物理尺寸为600x400像素
      my_screen.title("大画布小窗口示例") # 设置窗口标题
      
      # 设置画布逻辑尺寸为1000x800像素,背景色为浅灰色
      my_screen.screensize(canvwidth=1000, canvheight=800, bg="lightgray") # 调用screensize方法,将内部画布的宽度设置为1000像素,高度设置为800像素,并设置画布背景色为浅灰色。
      
      pen = turtle.Turtle() # 创建海龟对象
      pen.speed(0) # 设置最快速度
      pen.penup() # 抬笔
      pen.goto(-400, 300) # 移动到画布左上角附近
      pen.pendown() # 落笔
      
      # 在画布上绘制一个大矩形,超出当前窗口可见范围
      for _ in range(4): # 循环四次
          pen.forward(800) # 向前移动800单位
          pen.right(90) # 向右转90度
      
      my_screen.mainloop() # 启动事件循环
      
      • my_screen.setup(width=600, height=400): 将可见的绘图窗口大小设置为 600 像素宽、400 像素高。
      • my_screen.screensize(canvwidth=1000, canvheight=800, bg="lightgray"): 将实际的绘图画布大小设置为 1000 像素宽、800 像素高。由于画布大于窗口,当海龟移动到画布的边缘时,如果turtle没有提供滚动条(它通常不直接提供),那么超出窗口范围的绘图部分将不可见,但它们确实被绘制在了内部的“大画布”上。这行代码也把画布的背景颜色设置为浅灰色。
      • pen.speed(0): 将海龟的绘制速度设置为最快(0)。
      • pen.penup(): 抬起画笔,这样海龟移动时不会留下痕迹。
      • pen.goto(-400, 300): 将海龟移动到画布的 (-400, 300) 坐标。这个坐标在 600x400 的窗口中可能是不可见的,但在 1000x800 的画布中是可见的。
      • pen.pendown(): 落下画笔,准备开始绘图。
      • for _ in range(4):: 循环 4 次,用于绘制一个正方形。
      • pen.forward(800): 海龟向前移动 800 个单位。
      • pen.right(90): 海龟向右转 90 度。
      • 这个例子演示了screensize如何创建了一个比实际窗口更大的绘图区域,即使窗口显示不全,海龟仍然可以在这个更大的逻辑区域内绘制。
2.2.2 窗口标题与背景色:title()bgcolor()
  • screen.title(titlestring)

    • 作用:设置绘图窗口的标题。
    • 参数titlestring,一个字符串,作为窗口的标题栏文本。
    • 示例
      import turtle
      
      my_screen = turtle.Screen() # 创建屏幕对象
      my_screen.title("我的海龟绘图程序") # 设置窗口标题为“我的海龟绘图程序”
      my_screen.mainloop() # 启动事件循环
      
      • my_screen.title("我的海龟绘图程序"): 这行代码调用 Screen 对象的 title 方法,将绘图窗口的标题栏文本设置为“我的海龟绘图程序”。
  • screen.bgcolor(*args)

    • 作用:设置绘图窗口的背景颜色。
    • 参数:颜色参数可以是一个颜色名称字符串(如"red", “blue”, “green”),也可以是RGB颜色元组(如(0.5, 0.2, 0.8)),或者是RGB的十六进制字符串(如"#FF0000")。
    • 示例
      import turtle
      
      my_screen = turtle.Screen() # 创建屏幕对象
      my_screen.bgcolor("lightgreen") # 设置背景颜色为浅绿色
      # my_screen.bgcolor("#ADD8E6") # 另一种设置方式:使用十六进制颜色码,这里是浅蓝色
      # my_screen.bgcolor((0.5, 0.7, 0.9)) # 另一种设置方式:使用RGB元组,值范围0.0-1.0
      
      my_screen.mainloop() # 启动事件循环
      
      • my_screen.bgcolor("lightgreen"): 调用 Screen 对象的 bgcolor 方法,将绘图窗口的背景颜色设置为“浅绿色”。
2.2.3 事件循环与程序退出:mainloop()exitonclick()

这是turtle程序能够持续显示和响应用户交互的关键。

  • screen.mainloop() / turtle.done()

    • 作用:启动Tkinter的事件循环。一旦调用,程序将进入一个无限循环,等待并处理用户的输入(如鼠标点击、键盘按键)以及屏幕刷新等事件。如果没有这个循环,绘图窗口会一闪而过,或者直接关闭,因为Python脚本执行完毕后就会退出。
    • 注意mainloop()通常是程序的最后一行,因为它会阻塞程序的执行,直到窗口关闭。
    • **turtle.done()**是turtle.mainloop()的别名,功能完全相同。
    • 示例:已在之前的例子中多次使用。
  • screen.exitonclick()

    • 作用:注册一个事件监听器,使得当用户点击绘图窗口的任意位置时,窗口能够自动关闭。
    • 注意:这个方法内部会调用mainloop()来启动事件循环,因此通常不需要再手动调用mainloop()
    • 示例
      import turtle
      
      my_screen = turtle.Screen() # 创建屏幕对象
      my_screen.bgcolor("pink") # 设置背景颜色为粉色
      my_screen.title("点击我关闭!") # 设置窗口标题
      
      # 创建并移动一只海龟
      my_turtle = turtle.Turtle() # 创建海龟对象
      my_turtle.forward(100) # 海龟向前移动100单位
      my_turtle.left(120) # 海龟向左转120度
      my_turtle.forward(100) # 海龟继续向前移动100单位
      my_turtle.left(120) # 海龟向左转120度
      my_turtle.forward(100) # 海龟继续向前移动100单位,绘制一个等边三角形
      
      my_screen.exitonclick() # 注册点击事件,点击窗口即可关闭
      
      • my_screen.exitonclick(): 这行代码设置了一个事件监听器。当用户用鼠标点击绘图窗口的任何位置时,程序将接收到这个点击事件,并执行关闭窗口的操作。它内部包含了启动事件循环的功能,所以不需要再单独调用 mainloop()
2.2.4 清理与重置:clear()resetscreen()

Screen对象也提供了一些方法来清理或重置整个绘图环境。

  • screen.clear() / screen.clearscreen()

    • 作用:清空屏幕上的所有绘图内容(包括所有海龟绘制的图形和盖章),但重置屏幕的设置(如背景色、标题、窗口大小等)。所有海龟的位置和状态也不会改变。
    • 示例
      import turtle
      import time # 导入时间模块,用于暂停
      
      my_screen = turtle.Screen() # 创建屏幕对象
      my_screen.bgcolor("cyan") # 设置背景色为青色
      my_screen.title("屏幕清理示例") # 设置标题
      
      # 创建一个海龟
      pen = turtle.Turtle() # 创建海龟对象
      pen.pensize(2) # 设置笔的粗细为2像素
      pen.color("blue") # 设置笔的颜色为蓝色
      
      # 绘制一个正方形
      for _ in range(4): # 循环四次
          pen.forward(100) # 向前移动100单位
          pen.right(90) # 向右转90度
      
      time.sleep(2) # 暂停2秒,让用户看到绘制的图形 # 让程序暂停2秒钟,以便用户可以观察到已经绘制好的正方形。
      
      # 清空屏幕内容
      my_screen.clear() # 清空屏幕上所有的绘图内容,但是背景颜色和窗口标题等设置保持不变。海龟的位置和状态也不变。
      
      # 再次绘制,从海龟当前位置开始
      pen.forward(50) # 海龟(仍然在原先的位置和方向)向前移动50单位
      pen.left(60) # 海龟向左转60度
      pen.forward(50) # 海龟继续向前移动50单位
      
      my_screen.exitonclick() # 点击关闭
      
      • my_screen.clear(): 这行代码会清除绘图窗口中所有海龟绘制的图形和盖章,让屏幕变得干净。但是,屏幕的背景颜色(cyan)和标题(“屏幕清理示例”)以及所有海龟对象的位置和状态都不会被重置。所以,海龟 pen 在清空后会从它清空前的位置继续绘制。
  • screen.reset() / screen.resetscreen()

    • 作用完全重置整个绘图环境。它会:
      1. 清空屏幕上的所有绘图内容。
      2. 删除所有创建的海龟对象(除了一个默认的匿名海龟)。
      3. 将屏幕的所有设置(如背景色、标题、窗口大小、坐标模式等)恢复到默认状态。
      4. 默认的匿名海龟会回到屏幕中心,朝向东方(右方),笔抬起,颜色黑色,大小正常。
    • 示例
      import turtle
      import time
      
      my_screen = turtle.Screen() # 创建屏幕对象
      my_screen.bgcolor("yellow") # 设置背景色为黄色
      my_screen.title("屏幕重置示例") # 设置标题
      my_screen.setup(width=500, height=300) # 设置窗口尺寸
      
      # 创建一只海龟并绘制一些东西
      t1 = turtle.Turtle() # 创建第一个海龟对象
      t1.color("red") # 设置颜色为红色
      t1.forward(100) # 向前移动100单位
      t1.left(90) # 向左转90度
      t1.forward(50) # 向前移动50单位
      
      # 创建另一只海龟
      t2 = turtle.Turtle() # 创建第二个海龟对象
      t2.color("green") # 设置颜色为绿色
      t2.penup() # 抬笔
      t2.goto(-50, -50) # 移动到(-50, -50)坐标
      t2.pendown() # 落笔
      t2.circle(30) # 绘制一个半径为30的圆
      
      time.sleep(3) # 暂停3秒,观察所有绘制内容 # 暂停3秒,让用户有足够的时间观察两个海龟所绘制的内容。
      
      # 重置整个屏幕环境
      my_screen.reset() # 调用reset方法,这将彻底清空屏幕,删除所有自定义的海龟(t1和t2),并将屏幕的背景色、标题、尺寸等所有设置恢复到默认值。
      
      # 此时,t1和t2对象已经失效,尝试操作它们会报错。
      # 屏幕回到默认状态,如果需要继续绘图,需要重新创建海龟或操作默认海龟。
      
      # 默认的海龟(如果之前没有创建任何Turtle实例,或者所有实例被reset清除后,
      # 再次调用turtle模块的绘图函数,会作用于一个匿名的默认海龟)
      # 我们可以显式地获取一个新海龟或默认海龟来继续操作
      new_pen = turtle.Turtle() # 重置后,所有之前的海龟对象都已被删除,需要重新创建一个新的海龟对象来继续绘图。
      new_pen.write("屏幕已重置!", align="center", font=("Arial", 20, "normal")) # 在屏幕中心写入文本,表示屏幕已经重置。
      
      my_screen.exitonclick() # 点击关闭
      
      • my_screen.reset(): 这是一个强大的清理和重置方法。它不仅会清除屏幕上所有的绘图内容,还会删除所有通过 turtle.Turtle() 创建的海龟实例(如 t1t2),并且会将 Screen 对象的背景颜色、标题、窗口尺寸等所有设置恢复到其默认状态。这意味着,在 reset() 调用之后,如果您想继续绘图,需要重新创建海龟对象(或者 turtle 库会为您提供一个默认的匿名海龟)。

总结来说,clear()用于清除绘图痕迹但不改变环境配置,而reset()则是“大爆炸式”的重置,将一切恢复到初始状态。

2.2.5 坐标模式:setworldcoordinates()mode()

turtle支持两种主要的坐标模式。

  • screen.mode(mode=None)

    • 作用:设置或查询绘图模式。
    • 参数
      • "standard" (默认):海龟朝向0度为东方(正X轴),90度为北方(正Y轴)。角度增加方向为逆时针。屏幕中心为(0,0)。
      • "logo":海龟朝向0度为北方(正Y轴),90度为东方(正X轴)。角度增加方向为顺时针。屏幕中心为(0,0)。
      • "world":用户自定义坐标系。配合setworldcoordinates()使用。
    • 返回值:如果未提供参数,返回当前模式字符串。
    • 示例
      import turtle
      
      my_screen = turtle.Screen() # 创建屏幕对象
      my_screen.setup(width=400, height=400) # 设置窗口尺寸
      my_screen.title("坐标模式示例") # 设置标题
      
      pen = turtle.Turtle() # 创建海龟对象
      pen.speed(1) # 设置速度为1
      pen.shape("turtle") # 将海龟形状设置为真实的乌龟图标
      
      # 默认是"standard"模式
      print(f"当前坐标模式: {
               my_screen.mode()}") # 打印当前屏幕的坐标模式,默认是“standard”。
      
      pen.forward(100) # 向前移动100单位
      pen.left(90) # 向左转90度
      pen.forward(100) # 继续向前移动100单位
      
      # 切换到"logo"模式
      my_screen.mode("logo") # 将屏幕的坐标模式从“standard”切换到“logo”模式。
      print(f"切换后坐标模式: {
               my_screen.mode()}") # 打印切换后的坐标模式。
      
      # 此时0度是向上,90度是向右,且角度顺时针增加
      pen.setheading(0) # 将海龟的朝向设置为0度,在“logo”模式下意味着向上。
      pen.color("red") # 改变笔的颜色为红色
      pen.forward(100) # 向上移动100单位
      pen.right(90) # 向右转90度(顺时针),此时海龟朝向右
      pen.forward(100) # 向右移动100单位
      
      my_screen.exitonclick() # 点击关闭
      
      • my_screen.mode("logo"): 这行代码将绘图屏幕的坐标系统从默认的“standard”(0度向右,90度向上,逆时针增加角度)切换到“logo”模式(0度向上,90度向右,顺时针增加角度)。
      • pen.setheading(0): 在“logo”模式下,0度方向是向上(正Y轴),所以这行代码会使海龟面朝屏幕上方。
  • screen.setworldcoordinates(llx, lly, urx, ury)

    • 作用:定义一个用户自定义的坐标系统。这会将物理屏幕的矩形区域映射到您定义的逻辑坐标系统。
    • 参数
      • llx: 逻辑坐标系中左下角的X坐标。
      • lly: 逻辑坐标系中左下角的Y坐标。
      • urx: 逻辑坐标系中右上角的X坐标。
      • ury: 逻辑坐标系中右上角的Y坐标。
    • 注意:调用此方法后,屏幕模式会自动切换到"world"模式。这意味着您的绘图指令(如forwardgoto)将使用这个新的逻辑坐标系。
    • 示例
      import turtle
      
      my_screen = turtle.Screen() # 创建屏幕对象
      my_screen.setup(width=600, height=600) # 设置窗口尺寸为600x600像素
      my_screen.title("自定义世界坐标系示例") # 设置窗口标题
      
      # 设置自定义世界坐标系:左下角(-10, -10),右上角(10, 10)
      # 这样,屏幕的中心仍是(0,0),但X轴范围是-10到10,Y轴范围也是-10到10。
      # 屏幕的每个像素将代表这个逻辑坐标系中的一个小单位。
      my_screen.setworldcoordinates(-10, -10, 10, 10) # 将屏幕的逻辑坐标系设置为从左下角(-10, -10)到右上角(10, 10)。这样,绘图时使用的单位不再是像素,而是这个自定义坐标系中的逻辑单位。
      print(f"当前坐标模式: {
               my_screen.mode()}") # 打印当前坐标模式,此时应为“world”。
      
      pen = turtle.Turtle() # 创建海龟对象
      pen.speed(1) # 设置速度为1
      pen.shape("circle") # 设置海龟形状为圆形
      pen.color("blue") # 设置颜色为蓝色
      pen.pensize(2) # 设置笔的粗细为2
      
      # 现在,移动1个单位在视觉上会比默认模式下大很多,
      # 因为1个逻辑单位被映射到更多的物理像素。
      pen.penup() # 抬笔
      pen.goto(-9, 9) # 移动到自定义坐标系中的(-9, 9)点,即左上角附近。
      pen.pendown() # 落笔
      
      # 绘制一个在自定义坐标系下边长为18的正方形
      for _ in range(4): # 循环四次
          pen.forward(18) # 向前移动18个逻辑单位,相当于从-9移动到9。
          pen.right(90) # 向右转90度
      
      # 绘制中心点
      pen.penup() # 抬笔
      pen.goto(0, 0) # 移动到自定义坐标系的原点(0, 0)。
      pen.dot(5, "red") # 在原点绘制一个半径为5的红色点。
      
      my_screen.exitonclick() # 点击关闭
      
      • my_screen.setworldcoordinates(-10, -10, 10, 10): 这一行是 setworldcoordinates 方法的核心。它将绘图屏幕的左下角映射到逻辑坐标 (-10, -10),将右上角映射到逻辑坐标 (10, 10)。这意味着屏幕上的 X 轴范围是 -10 到 10,Y 轴范围也是 -10 到 10。因此,当海龟移动 1 个单位时,它在屏幕上实际移动的像素距离会根据这个新的映射关系进行缩放。例如,如果窗口是 600x600 像素,那么 X 轴的 20 个逻辑单位(从 -10 到 10)将对应 600 像素,所以每个逻辑单位就是 30 像素。
2.2.6 动画控制与性能优化:tracer()update()

对于复杂的绘图,turtle库的默认动画效果可能会非常慢。tracer()update()方法可以显著提高绘图速度。

  • screen.tracer(n=None, delay=None)

    • 作用:开启/关闭自动屏幕刷新,并控制刷新的频率。这是性能优化的关键。
    • 参数
      • n: 如果设置为大于0的整数,表示每n个海龟动作后刷新一次屏幕。如果设置为0,则关闭自动刷新,需要手动调用screen.update()
      • delay: 每两次屏幕刷新之间的延迟时间(毫秒)。
    • 返回值:如果未提供参数,返回当前的n值。
    • 注意:当tracer(0)关闭自动刷新时,所有绘图操作都不会立即显示,直到update()被调用。这对于绘制复杂图形非常有用,因为它避免了频繁的屏幕重绘,从而大大提高了速度。
    • 示例
      import turtle
      import random # 导入random模块,用于生成随机数
      
      my_screen = turtle.Screen() # 创建屏幕对象
      my_screen.setup(width=700, height=700) # 设置窗口尺寸
      my_screen.bgcolor("black") # 设置背景色为黑色
      my_screen.title("使用tracer进行快速绘制") # 设置标题
      
      # 关闭自动刷新
      my_screen.tracer(0) # 将自动屏幕刷新设置为关闭状态(0),这意味着后续的海龟操作将不会立即在屏幕上显示出来,直到调用my_screen.update()。
      
      pen = turtle.Turtle() # 创建海龟对象
      pen.speed(0) # 设置海龟的绘制速度为最快(0,尽管tracer(0)已经控制了刷新,但这个仍然影响内部计算)。
      pen.color("lime") # 设置笔的颜色为亮绿色
      pen.pensize(1) # 设置笔的粗细为1像素
      pen.penup() # 抬笔
      pen.goto(-300, 300) # 移动到左上角附近
      pen.pendown() # 落笔
      
      # 绘制大量随机线段
      for _ in range(500): # 循环500次,绘制500条线段
          length = random.randint(10, 50) # 随机生成线段长度
          angle = random.randint(-180, 180) # 随机生成转动角度
          pen.forward(length) # 海龟向前移动指定长度
          pen.left(angle) # 海龟向左转动指定角度
      
      # 所有绘制完成后,一次性更新屏幕
      my_screen.update() # 强制屏幕进行一次完整的刷新,将所有之前未显示的绘图内容一次性渲染出来。
      
      my_screen.exitonclick() # 点击关闭
      
      • my_screen.tracer(0): 这是提高绘图速度的关键。当参数为 0 时,tracer 方法会关闭 turtle 的自动屏幕更新功能。这意味着海龟的每一次移动和绘图操作都不会立即在屏幕上显示出来,而是先在内部缓冲区中完成。
      • my_screen.update(): 这行代码在所有的绘图操作(这里是 500 次随机线段的绘制)完成后被调用。它的作用是强制 turtle 刷新屏幕,将缓冲区中的所有绘图内容一次性地渲染出来。这样可以避免频繁的屏幕重绘带来的性能开销,使得复杂的图形能够以极快的速度完成绘制。
  • screen.update()

    • 作用:当screen.tracer(0)被调用关闭自动刷新时,update()用于手动触发屏幕的刷新。
    • 注意:如果tracer没有被设置为0,update()通常不需要手动调用,因为屏幕会自动刷新。
    • 示例:参见tracer()的示例。
2.2.7 其他常用Screen方法
  • screen.getcanvas()

    • 作用:返回turtle绘图所使用的Tkinter画布对象。这对于高级用户想直接操作Tkinter的特性非常有用。
    • 示例
      import turtle
      
      my_screen = turtle.Screen() # 创建屏幕对象
      canvas = my_screen.getcanvas() # 获取底层的Tkinter画布对象
      print(f"Tkinter画布对象类型: {
               type(canvas)}") # 打印画布对象的类型,通常是tkinter.Canvas
      my_screen.exitonclick() # 点击关闭
      
      • canvas = my_screen.getcanvas(): 这行代码获取了 turtle 绘图窗口背后使用的 Tkinter Canvas 对象。turtle 库实际上是 Tkinter 的一个上层封装,所有图形的绘制最终都是通过 Tkinter 的 Canvas 组件完成的。了解这一点对于需要进行更底层 Tkinter 操作的开发者很有用。
  • screen.numinput(title, prompt, default=None, minval=None, maxval=None)

    • 作用:弹出一个对话框,允许用户输入一个数字。
    • 参数
      • title: 对话框的标题。
      • prompt: 提示用户输入的文本。
      • default: 默认值(可选)。
      • minval: 允许的最小值(可选)。
      • maxval: 允许的最大值(可选)。
    • 返回值:用户输入的数字(浮点数),如果用户取消输入,则返回None
    • 示例
      import turtle
      
      my_screen = turtle.Screen() # 创建屏幕对象
      my_screen.title("数字输入") # 设置标题
      
      # 弹出一个数字输入框
      user_input_length = my_screen.numinput("绘制长度", "请输入要绘制的线段长度 (10-200):", default=100, minval=10, maxval=200) # 弹出一个数字输入对话框,标题为“绘制长度”,提示文本为“请输入要绘制的线段长度 (10-200):”,默认值为100,最小值为10,最大值为200。用户输入的数字将被赋值给user_input_length。
      
      if user_input_length is not None: # 如果用户没有取消输入(即user_input_length不为None)
          pen = turtle.Turtle() # 创建海龟对象
          pen.shape("arrow") # 设置海龟形状为箭头
          pen.forward(user_input_length) # 海龟向前移动用户输入的长度
      
      my_screen.exitonclick() # 点击关闭
      
      • user_input_length = my_screen.numinput(...): 这行代码会弹出一个小对话框,要求用户输入一个数字。对话框的标题是“绘制长度”,提示语是“请输入要绘制的线段长度 (10-200):”,并且提供了默认值 100,以及输入范围 10 到 200。用户的有效数字输入会被存储到 user_input_length 变量中;如果用户点击了“取消”按钮,user_input_length 将会是 None
  • screen.textinput(title, prompt)

    • 作用:弹出一个对话框,允许用户输入一个文本字符串。
    • 参数
      • title: 对话框的标题。
      • prompt: 提示用户输入的文本。
    • 返回值:用户输入的字符串,如果用户取消输入,则返回None
    • 示例
      import turtle
      
      my_screen = turtle.Screen() # 创建屏幕对象
      my_screen.title("文本输入") # 设置标题
      
      # 弹出一个文本输入框
      user_text = my_screen.textinput("问候语", "请输入您的名字:") # 弹出一个文本输入对话框,标题为“问候语”,提示文本为“请输入您的名字:”。用户输入的文本将被赋值给user_text。
      
      if user_text is not None: # 如果用户没有取消输入
          pen = turtle.Turtle() # 创建海龟对象
          pen.hideturtle() # 隐藏海龟
          pen.penup() # 抬笔
          pen.goto(0, 50) # 移动到(0, 50)坐标
          pen.write(f"你好, {
               user_text}!", align="center", font=("Arial", 24, "bold")) # 在屏幕上写入问候语,包含用户输入的名字,居中对齐,使用Arial字体,大小24,粗体。
      
      my_screen.exitonclick() # 点击关闭
      
      • user_text = my_screen.textinput(...): 这行代码会弹出一个小对话框,要求用户输入文本。对话框标题是“问候语”,提示语是“请输入您的名字:”。用户输入的文本会被存储到 user_text 变量中;如果用户点击了“取消”按钮,user_text 将会是 None
  • screen.ontimer(fun, t=0)

    • 作用:注册一个定时器,在t毫秒后执行一次函数fun
    • 参数
      • fun: 要调用的函数。
      • t: 延迟时间,单位毫秒。
    • 注意:这是一个一次性定时器。如果需要重复执行,需要在fun函数内部再次调用ontimer
    • 示例
      import turtle
      
      my_screen = turtle.Screen() # 创建屏幕对象
      my_screen.title("定时器示例") # 设置标题
      
      pen = turtle.Turtle() # 创建海龟对象
      pen.hideturtle() # 隐藏海龟
      pen.penup() # 抬笔
      pen.goto(0, 100) # 移动到(0, 100)坐标
      
      counter = 0 # 初始化计数器
      
      def update_text(): # 定义一个函数,用于更新屏幕上的文本
          nonlocal counter # 声明使用外部作用域的counter变量
          pen.clear() # 清空海龟之前的写入内容
          pen.write(f"计数: {
               counter}", align="center", font=("Arial", 30, "normal")) # 在屏幕上写入当前计数器的值
          counter += 1 # 计数器加1
          my_screen.ontimer(update_text, 1000) # 1000毫秒(1秒)后再次调用自身,实现重复定时执行
      
      my_screen.ontimer(update_text, 1000) # 启动第一个定时器,1秒后开始执行update_text函数 # 第一次调用 `ontimer` 方法,它会安排 `update_text` 函数在 1000 毫秒(即 1 秒)后执行一次。`update_text` 函数内部又会再次调用 `ontimer` 来实现每秒重复执行的效果。
      
      my_screen.mainloop() # 启动事件循环
      
      • my_screen.ontimer(update_text, 1000): 这一行代码注册了一个定时器。它的作用是告诉 turtle 库,在 1000 毫秒(即 1 秒)之后,执行一次 update_text 函数。由于 update_text 函数内部又会再次调用 my_screen.ontimer(update_text, 1000),这就形成了一个递归的定时调用,从而实现了每秒更新一次屏幕上计数值的动画效果。

2.3 海龟(Turtle)对象的创建与初始化

海龟对象是实际进行绘图操作的主体。您可以创建多个海龟,它们可以独立移动、改变颜色、改变形状,甚至可以同时在屏幕上绘制。

创建Turtle对象:

import turtle # 导入turtle模块

# 获取屏幕对象(如果之前没有创建过)
my_screen = turtle.Screen() # 获取或创建默认的屏幕对象

# 创建一个海龟对象
# 您可以创建多个海龟,每个海龟都是一个独立的绘图实体
artist_turtle = turtle.Turtle() # 创建Turtle类的一个实例,并将其赋值给artist_turtle变量。这个对象就是我们在屏幕上看到并控制的海龟。
  • my_screen = turtle.Screen(): 创建一个 Screen 对象,代表绘图窗口。
  • artist_turtle = turtle.Turtle(): 创建一个 Turtle 对象,代表屏幕上的绘图海龟。您可以创建任意多个 Turtle 实例,每个实例都可以独立地进行绘图和移动。

默认海龟的属性:

当您第一次创建turtle.Turtle()对象时,它会带有一些默认的属性:

  • 位置:屏幕中心 (0, 0)。
  • 朝向:向右(东),即0度。
  • 形状:经典的“箭头”形状。
  • 颜色:笔迹颜色为黑色,填充颜色也为黑色。
  • 笔的状态:落笔(pendown()),意味着移动时会留下痕迹。
  • 笔的粗细:通常是1像素。
  • 速度:正常速度(默认值6)。

多个海龟对象的使用:

import turtle

my_screen = turtle.Screen() # 创建屏幕对象
my_screen.bgcolor("gray") # 设置背景色为灰色
my_screen.title("多只海龟协作绘图") # 设置标题
my_screen.setup(width=700, height=500) # 设置窗口尺寸

# 创建第一只海龟:红色箭头
red_turtle = turtle.Turtle() # 创建第一个海龟对象
red_turtle.shape("arrow") # 设置形状为箭头
red_turtle.color("red") # 设置颜色为红色
red_turtle.pensize(3) # 设置笔的粗细为3像素
red_turtle.penup() # 抬笔
red_turtle.goto(-200, 100) # 移动到屏幕左上角附近
red_turtle.pendown() # 落笔

# 绘制一个正方形
for _ in range(4): # 循环四次
    red_turtle.forward(150) # 向前移动150单位
    red_turtle.right(90) # 向右转90度

# 创建第二只海龟:蓝色海龟形状
blue_turtle = turtle.Turtle() # 创建第二个海龟对象
blue_turtle.shape("turtle") # 设置形状为海龟图标
blue_turtle.color("blue") # 设置颜色为蓝色
blue_turtle.pensize(2) # 设置笔的粗细为2像素
blue_turtle.penup() # 抬笔
blue_turtle.goto(100, -100) # 移动到屏幕右下角附近
blue_turtle.pendown() # 落笔

# 绘制一个圆形
blue_turtle.circle(80) # 绘制一个半径为80的圆形

# 创建第三只海龟:绿色点点形状
green_dot_turtle = turtle.Turtle() # 创建第三个海龟对象
green_dot_turtle.shape("circle") # 设置形状为圆形
green_dot_turtle.color("green") # 设置颜色为绿色
green_dot_turtle.penup() # 抬笔
green_dot_turtle.goto(0, 0) # 移动到屏幕中心
green_dot_turtle.pendown() # 落笔
green_dot_turtle.dot(10, "green") # 在当前位置绘制一个半径为10的绿色点 # 在当前海龟位置绘制一个直径为10个单位的绿色圆点。

my_screen.exitonclick() # 点击关闭
  • red_turtle = turtle.Turtle(): 创建第一个名为 red_turtle 的海龟对象。
  • blue_turtle = turtle.Turtle(): 创建第二个名为 blue_turtle 的海龟对象。
  • green_dot_turtle = turtle.Turtle(): 创建第三个名为 green_dot_turtle 的海龟对象。
  • 这个例子展示了如何创建和同时控制多只海龟。每只海龟都是独立的,拥有自己的颜色、形状、位置、方向和绘图状态,它们可以在屏幕上独立地执行绘图任务,实现更复杂的复合图形。

第三章:海龟运动的原子操作与核心概念

海龟绘图的核心在于控制一只虚拟的“海龟”在屏幕上移动,并在其移动路径上绘制图形。本章将深入剖析海龟的各种运动指令,从最基本的向前、向后移动,到复杂的绝对定位和方向调整,揭示其背后的数学原理和交互逻辑。

3.1 海龟的坐标系统与默认状态

在深入学习海龟的移动指令之前,我们必须理解turtle库所使用的坐标系统。默认情况下,turtle库采用的是标准的笛卡尔直角坐标系,其原点(0, 0)位于绘图窗口的中心。

  • X轴:水平方向。正方向向右,负方向向左。
  • Y轴:垂直方向。正方向向上,负方向向下。

海龟的默认初始状态:

当您创建一个新的turtle.Turtle()对象时,它会处于以下默认状态:

  • 位置(0, 0),即屏幕中心。
  • 朝向0度,即正东方(沿X轴正方向)。
  • 笔的状态pendown()(落笔),即移动时会留下笔迹。
  • 笔的颜色:黑色。
  • 笔的粗细:1像素。
  • 形状:经典的“箭头” ('arrow')。
  • 速度6(中等速度)。

理解这些默认状态对于预测海龟行为至关重要。

3.2 基本移动指令:forward(), backward(), fd(), bk()

这是海龟最常用、最直观的移动指令,它们控制海龟沿着当前朝向移动。

3.2.1 turtle.forward(distance)turtle.fd(distance)
  • 作用:使海龟沿着其当前朝向向前移动指定的距离。
  • 参数distance,一个数字,表示移动的距离。正值表示向前移动,负值表示向后移动(与backward()效果相同,但不推荐使用负值替代backward,因为可读性较差)。
  • 返回值:无。
  • 绘图行为:如果笔是落下的(pendown),海龟会留下笔迹;如果笔是抬起的(penup),则不会留下笔迹。
  • 内部机制:海龟的X、Y坐标会根据其当前朝向和移动距离进行更新。假设海龟当前朝向角度为 A (弧度制),移动距离为 D,则其X坐标变化为 ( \Delta X = D \cdot \cos(A) ),Y坐标变化为 ( \Delta Y = D \cdot \sin(A) )。这是直角坐标系中向量分解的基本原理。
  • 示例:绘制一条直线
    import turtle # 导入turtle模块
    
    my_screen = turtle.Screen() # 创建屏幕对象
    my_screen.bgcolor("lightyellow") # 设置屏幕背景色为浅黄色
    my_screen.title("Forward方法演示") # 设置窗口标题
    
    artist = turtle.Turtle() # 创建一个海龟对象
    artist.shape("turtle") # 将海龟的形状设置为“turtle”图标
    artist.color("blue") # 设置海龟的笔颜色为蓝色
    artist.pensize(5) # 设置海龟的笔粗细为5像素
    
    print(f"初始位置: {
           artist.pos()}, 初始朝向: {
           artist.heading()}度") # 打印海龟的初始位置和朝向
    
    artist.forward(100) # 海龟向前移动100个单位距离
    print(f"移动100后位置: {
           artist.pos()}, 朝向: {
           artist.heading()}度") # 打印海龟移动100单位后的位置和朝向
    
    artist.fd(50) # 海龟继续向前移动50个单位距离(fd是forward的缩写)
    print(f"再移动50后位置: {
           artist.pos()}, 朝向: {
           artist.heading()}度") # 打印海龟再次移动50单位后的位置和朝向
    
    my_screen.exitonclick() # 点击窗口关闭程序
    
    • my_screen = turtle.Screen(): 创建一个 Screen 类的实例,用于管理绘图窗口。
    • my_screen.bgcolor("lightyellow"): 设置绘图窗口的背景颜色为浅黄色。
    • my_screen.title("Forward方法演示"): 设置绘图窗口的标题。
    • artist = turtle.Turtle(): 创建一个 Turtle 类的实例,代表屏幕上的海龟,并将其赋值给 artist 变量。
    • artist.shape("turtle"): 将 artist 海龟的形状更改为经典的“海龟”图标,而非默认的箭头。
    • artist.color("blue"): 设置 artist 海龟绘图时的笔颜色为蓝色。
    • artist.pensize(5): 设置 artist 海龟绘图时笔的粗细为 5 像素。
    • print(f"初始位置: {artist.pos()}, 初始朝向: {artist.heading()}度"): 打印海龟在执行任何移动命令之前的当前位置(坐标)和当前朝向(角度)。
    • artist.forward(100): 让 artist 海龟沿着其当前朝向(默认是正东,0度)向前移动 100 个单位。由于笔是落下的,它会在屏幕上绘制一条蓝色的粗线。
    • print(f"移动100后位置: {artist.pos()}, 朝向: {artist.heading()}度"): 再次打印海龟移动 100 单位后的新位置和朝向,可以看到 X 坐标增加了 100。
    • artist.fd(50): fd()forward() 的一个更短的别名,功能完全相同。这行代码让海龟继续向前移动 50 个单位。
    • print(f"再移动50后位置: {artist.pos()}, 朝向: {artist.heading()}度"): 打印海龟再次移动后的位置和朝向,X 坐标又增加了 50。
    • my_screen.exitonclick(): 启动事件循环,并设置当用户点击绘图窗口时关闭程序。
3.2.2 turtle.backward(distance)turtle.bk(distance)turtle.back(distance)
  • 作用:使海龟沿着其当前朝向的反方向向后移动指定的距离。
  • 参数distance,一个数字,表示移动的距离。正值表示向后移动。
  • 返回值:无。
  • 绘图行为:与forward()相同,取决于笔的状态。
  • 内部机制:与forward()类似,但方向是反的。X、Y坐标的变化量是 forward() 的负值。假设海龟当前朝向角度为 A (弧度制),移动距离为 D,则其X坐标变化为 ( \Delta X = -D \cdot \cos(A) ),Y坐标变化为 ( \Delta Y = -D \cdot \sin(A) )。
  • 示例:绘制一个“回”字形
    import turtle # 导入turtle模块
    
    my_screen = turtle.Screen() # 创建屏幕对象
    my_screen.bgcolor("lavender") # 设置屏幕背景色为淡紫色
    my_screen.title("Backward方法演示") # 设置窗口标题
    
    artist = turtle.Turtle() # 创建海龟对象
    artist.shape("square") # 将海龟的形状设置为正方形
    artist.color("purple") # 设置海龟的笔颜色为紫色
    artist.pensize(4) # 设置海龟的笔粗细为4像素
    
    artist.penup() # 抬笔
    artist.goto(-100, 0) # 移动到(-100, 0)位置,不留痕迹
    artist.pendown() # 落笔
    
    # 绘制外层正方形的一条边
    artist.forward(200) # 海龟向前移动200单位
    artist.left(90) # 海龟向左转90度
    artist.forward(200) # 海龟向前移动200单位
    artist.left(90) # 海龟向左转90度
    artist.forward(200) # 海龟向前移动200单位
    artist.left(90) # 海龟向左转90度
    artist.forward(200) # 海龟向前移动200单位
    artist.left(90) # 海龟向左转90度 (回到起点和原方向)
    
    artist.penup() # 抬笔
    artist.backward(50) # 海龟向后移动50单位(从(100,0)到(50,0))
    artist.right(90) # 海龟向右转90度
    artist.forward(50) # 海龟向前移动50单位 (进入内侧)
    artist.left(90) # 海龟向左转90度
    artist.pendown() # 落笔
    
    # 绘制内层正方形
    for _ in range(4): # 循环四次
        artist.forward(100) # 海龟向前移动100单位
        artist.right(90) # 海龟向右转90度
    
    my_screen.exitonclick() # 点击窗口关闭程序
    
    • my_screen.bgcolor("lavender"): 设置屏幕背景色为淡紫色。
    • artist.shape("square"): 将海龟形状设置为正方形。
    • artist.color("purple"): 设置笔颜色为紫色。
    • artist.pensize(4): 设置笔粗细为 4 像素。
    • artist.penup(): 抬起画笔,移动时不留痕迹。
    • artist.goto(-100, 0): 将海龟移动到坐标 (-100, 0)
    • artist.pendown(): 落下画笔,开始绘图。
    • 绘制外层正方形:通过四次 forward(200)left(90) 绘制一个边长为 200 的正方形。
    • artist.penup(): 再次抬笔。
    • artist.backward(50): backward() 方法让海龟沿着当前方向的反方向移动。在绘制完外层正方形回到 (-100, 0) 且朝向 0 度后,backward(50) 会让海龟移动到 (-150, 0),但这里海龟最后一次 forward(200) 是到 (100,0),再 left(90) 之后是面向北方。所以 backward(50) 是从 (100, 200)(假设初始goto点是(-100,0)且海龟画完外框回到原点方向不变)沿北方方向向后移动50,即向下移动50。更正:在绘制完外层正方形后,海龟最终会回到 (-100, 0) 并且朝向 0 度(向右)。因此 artist.backward(50) 会使其从 (-100, 0) 向左移动 50 个单位,到达 (-150, 0)
    • artist.right(90): 海龟向右转 90 度。
    • artist.forward(50): 海龟向前移动 50 单位。
    • artist.left(90): 海龟向左转 90 度。
    • artist.pendown(): 再次落笔。
    • 绘制内层正方形:通过四次 forward(100)right(90) 绘制一个边长为 100 的正方形。
    • my_screen.exitonclick(): 启动事件循环,并设置点击窗口关闭。

3.3 转向指令:left(), right(), lt(), rt()

除了移动,控制海龟的朝向也是绘图的关键。这些指令让海龟在原地旋转,而不改变其X、Y坐标。

3.3.1 turtle.left(angle)turtle.lt(angle)
  • 作用:使海龟向左(逆时针)旋转指定的角度。
  • 参数angle,一个数字,表示旋转的角度(默认为度数)。
  • 返回值:无。
  • 内部机制:海龟的内部朝向角度会增加 angle
  • 示例:绘制一个星形
    import turtle # 导入turtle模块
    
    my_screen = turtle.Screen() # 创建屏幕对象
    my_screen.bgcolor("black") # 设置屏幕背景色为黑色
    my_screen.title("Left方法绘制五角星") # 设置窗口标题
    
    star_pen = turtle.Turtle() # 创建海龟对象
    star_pen.speed(5) # 设置海龟速度为5
    star_pen.color("gold") # 设置笔颜色为金色
    star_pen.pensize(2) # 设置笔粗细为2像素
    
    star_pen.penup() # 抬笔
    star_pen.goto(-100, 50) # 移动到(-100, 50)位置
    star_pen.pendown() # 落笔
    
    # 绘制五角星
    for _ in range(5): # 循环五次
        star_pen.forward(200) # 海龟向前移动200单位
        star_pen.left(144) # 海龟向左转144度(五角星的内角是36度,外角是144度)
    
    my_screen.exitonclick() # 点击窗口关闭程序
    
    • my_screen.bgcolor("black"): 设置背景色为黑色。
    • star_pen.speed(5): 设置海龟速度为 5。
    • star_pen.color("gold"): 设置笔颜色为金色。
    • star_pen.pensize(2): 设置笔粗细为 2 像素。
    • star_pen.penup(): 抬笔。
    • star_pen.goto(-100, 50): 移动到 (-100, 50)
    • star_pen.pendown(): 落笔。
    • for _ in range(5):: 循环 5 次以绘制五角星的 5 条边。
    • star_pen.forward(200): 绘制一条 200 单位长的线段。
    • star_pen.left(144): 这是绘制五角星的关键一步。在绘制每条边之后,海龟需要向左转 144 度,以便下一条边能够正确连接并形成星形。
3.3.2 turtle.right(angle)turtle.rt(angle)
  • 作用:使海龟向右(顺时针)旋转指定的角度。
  • 参数angle,一个数字,表示旋转的角度(默认为度数)。
  • 返回值:无。
  • 内部机制:海龟的内部朝向角度会减小 angle
  • 示例:绘制一个螺旋线
    import turtle # 导入turtle模块
    
    my_screen = turtle.Screen() # 创建屏幕对象
    my_screen.bgcolor("white") # 设置屏幕背景色为白色
    my_screen.title("Right方法绘制螺旋线") # 设置窗口标题
    
    spiral_pen = turtle.Turtle() # 创建海龟对象
    spiral_pen.speed(0) # 设置海龟速度为最快(0)
    spiral_pen.color("darkgreen") # 设置笔颜色为深绿色
    spiral_pen.pensize(2) # 设置笔粗细为2像素
    
    length = 5 # 初始化线段长度
    for i in range(100): # 循环100次,绘制螺旋线
        spiral_pen.forward(length) # 海龟向前移动当前长度
        spiral_pen.right(90) # 海龟向右转90度
        length += 2 # 每次移动后增加线段长度,使螺旋线逐渐变大
    
    my_screen.exitonclick() # 点击窗口关闭程序
    
    • spiral_pen.speed(0): 将海龟速度设置为最快,以便快速绘制复杂的螺旋线。
    • spiral_pen.color("darkgreen"): 设置笔颜色为深绿色。
    • spiral_pen.pensize(2): 设置笔粗细为 2 像素。
    • length = 5: 初始化线段的起始长度为 5。
    • for i in range(100):: 循环 100 次,每次循环绘制螺旋线的一小段。
    • spiral_pen.forward(length): 海龟向前移动当前 length 距离。
    • spiral_pen.right(90): 海龟向右转 90 度,这是形成螺旋的关键。
    • length += 2: 每次迭代后,将 length 增加 2,使得下一段线段更长,从而创建逐渐扩大的螺旋效果。

3.4 绝对定位指令:goto(), setx(), sety(), setposition()

这些指令允许海龟直接跳到屏幕上的某个精确位置,而不是基于其当前位置和朝向进行相对移动。

3.4.1 turtle.goto(x, y)turtle.setposition(x, y)turtle.setpos(x, y)
  • 作用:使海龟瞬间移动到指定的(x, y)坐标。
  • 参数x,目标X坐标;y,目标Y坐标。可以传入两个独立的数字参数,也可以传入一个包含两个数字的元组/列表,如(x, y)
  • 返回值:无。
  • 绘图行为:如果笔是落下的,goto()会绘制一条从当前位置到目标位置的直线。如果笔是抬起的,则不绘制。
  • 内部机制:直接修改海龟的内部X、Y坐标。朝向不会改变,除非新位置与旧位置在同一条直线上。如果旧位置和新位置不在同一条直线上,海龟会直接“瞬移”过去。
  • 示例:绘制多边形(通过指定顶点)
    import turtle # 导入turtle模块
    
    my_screen = turtle.Screen() # 创建屏幕对象
    my_screen.setup(width=600, height=600) # 设置窗口尺寸为600x600像素
    my_screen.bgcolor("darkblue") # 设置背景色为深蓝色
    my_screen.title("Goto方法绘制多边形") # 设置窗口标题
    
    poly_pen = turtle.Turtle() # 创建海龟对象
    poly_pen.speed(1) # 设置速度为1(慢速,方便观察)
    poly_pen.color("white") # 设置笔颜色为白色
    poly_pen.pensize(3) # 设置笔粗细为3像素
    poly_pen.shape("triangle") # 设置海龟形状为三角形
    
    # 定义多边形的顶点坐标(以屏幕中心(0,0)为参考)
    vertices = [
        (0, 200),     # 顶点1
        (150, 50),    # 顶点2
        (100, -150),  # 顶点3
        (-100, -150), # 顶点4
        (-150, 50)    # 顶点5
    ] # 定义一个列表,包含多边形所有顶点的坐标。
    
    poly_pen.penup() # 抬笔
    poly_pen.goto(vertices[0]) # 移动到第一个顶点,不绘制线条
    poly_pen.pendown() # 落笔
    
    # 依次连接所有顶点
    for vertex in vertices: # 遍历顶点列表
        poly_pen.goto(vertex) # 海龟移动到当前顶点坐标,并在移动过程中绘制线条
    
    # 回到起点,闭合多边形
    poly_pen.goto(vertices[0]) # 海龟移动回第一个顶点,闭合多边形
    
    my_screen.exitonclick() # 点击窗口关闭程序
    
    • my_screen.setup(width=600, height=600): 设置窗口尺寸为 600x600 像素。
    • my_screen.bgcolor("darkblue"): 设置背景色为深蓝色。
    • poly_pen.speed(1): 设置海龟速度为 1。
    • poly_pen.color("white"): 设置笔颜色为白色。
    • poly_pen.pensize(3): 设置笔粗细为 3 像素。
    • poly_pen.shape("triangle"): 将海龟形状设置为三角形。
    • vertices = [...]: 定义了一个列表,其中包含了多边形各个顶点的 (x, y) 坐标。
    • poly_pen.penup(): 抬起画笔,这样初始移动到第一个顶点时不会留下痕迹。
    • poly_pen.goto(vertices[0]): 使用 goto() 方法将海龟直接移动到 vertices 列表中的第一个顶点((0, 200))。
    • poly_pen.pendown(): 落下画笔,准备开始绘制。
    • for vertex in vertices:: 循环遍历 vertices 列表中的每一个顶点。
    • poly_pen.goto(vertex): 在循环中,海龟会逐个地移动到 vertices 中的每一个顶点。由于笔是落下的,每次移动都会绘制一条从当前位置到目标位置的直线。
    • poly_pen.goto(vertices[0]): 在循环结束后,为了确保多边形是闭合的,海龟会再次移动回第一个顶点。
3.4.2 turtle.setx(x)
  • 作用:将海龟的X坐标设置为指定值,Y坐标不变。
  • 参数x,目标X坐标。
  • 返回值:无。
  • 绘图行为:如果笔是落下的,会绘制一条水平线到新的X坐标。
  • 内部机制:只修改海龟的X坐标。
  • 示例:绘制X轴刻度线
    import turtle # 导入turtle模块
    
    my_screen = turtle.Screen() # 创建屏幕对象
    my_screen.bgcolor("beige") # 设置背景色为米色
    my_screen.title("Setx方法演示") # 设置窗口标题
    my_screen.tracer(0) # 关闭自动刷新,提高效率
    
    ruler_pen = turtle.Turtle() # 创建海龟对象
    ruler_pen.speed(0) # 设置最快速度
    ruler_pen.hideturtle() # 隐藏海龟图标
    ruler_pen.pensize(1) # 设置笔粗细为1像素
    ruler_pen.color("gray") # 设置笔颜色为灰色
    
    # 绘制X轴
    ruler_pen.penup() # 抬笔
    ruler_pen.goto(-250, 0) # 移动到X轴左端
    ruler_pen.pendown() # 落笔
    ruler_pen.goto(250, 0) # 绘制X轴到右端
    
    # 绘制刻度
    for x_coord in range(-200, 201, 50): # 从-200到200,步长为50
        ruler_pen.penup() # 抬笔
        ruler_pen.goto(x_coord, -10) # 移动到刻度线底部
        ruler_pen.pendown() # 落笔
        ruler_pen.sety(10) # 设置Y坐标为10,绘制垂直刻度线到顶部
        ruler_pen.penup() # 抬笔
        ruler_pen.goto(x_coord, -30) # 移动到刻度数字下方
        ruler_pen.write(f"{
           x_coord}", align="center", font=("Arial", 8, "normal")) # 写入刻度数字
    
    my_screen.update() # 手动更新屏幕
    my_screen.exitonclick() # 点击窗口关闭程序
    
    • my_screen.tracer(0): 关闭自动刷新以提高绘制大量刻度线的效率。
    • ruler_pen.hideturtle(): 隐藏海龟图标,因为我们主要关注绘制的刻度。
    • ruler_pen.penup(): 抬笔,以便移动到起始点时不留痕迹。
    • ruler_pen.goto(-250, 0): 将海龟移动到 X 轴的左端点 (-250, 0)
    • ruler_pen.pendown(): 落下画笔,准备绘制 X 轴。
    • ruler_pen.goto(250, 0): 绘制 X 轴到 (250, 0)
    • for x_coord in range(-200, 201, 50):: 循环生成从 -200 到 200,步长为 50 的 X 坐标值。
    • ruler_pen.penup(): 抬笔。
    • ruler_pen.goto(x_coord, -10): 移动到当前 X 坐标,Y 坐标为 -10(刻度线底部)。
    • ruler_pen.pendown(): 落笔。
    • ruler_pen.sety(10): 核心用法:将海龟的 Y 坐标直接设置为 10,X 坐标保持不变。由于笔是落下的,这将绘制一条从 (x_coord, -10)(x_coord, 10) 的垂直线段,形成刻度线。
    • ruler_pen.penup(): 抬笔。
    • ruler_pen.goto(x_coord, -30): 移动到刻度数字下方的位置。
    • ruler_pen.write(f"{x_coord}", ...): 写入当前刻度值。
    • my_screen.update(): 强制刷新屏幕,显示所有绘制内容。
3.4.3 turtle.sety(y)
  • 作用:将海龟的Y坐标设置为指定值,X坐标不变。
  • 参数y,目标Y坐标。
  • 返回值:无。
  • 绘图行为:如果笔是落下的,会绘制一条垂直线到新的Y坐标。
  • 内部机制:只修改海龟的Y坐标。
  • 示例:绘制Y轴刻度线
    import turtle # 导入turtle模块
    
    my_screen = turtle.Screen() # 创建屏幕对象
    my_screen.bgcolor("ivory") # 设置背景色为象牙色
    my_screen.title("Sety方法演示") # 设置窗口标题
    my_screen.tracer(0) # 关闭自动刷新
    
    ruler_pen = turtle.Turtle() # 创建海龟对象
    ruler_pen.speed(0) # 设置最快速度
    ruler_pen.hideturtle() # 隐藏海龟图标
    ruler_pen.pensize(1) # 设置笔粗细为1像素
    ruler_pen.color("brown") # 设置笔颜色为棕色
    
    # 绘制Y轴
    ruler_pen.penup() # 抬笔
    ruler_pen.goto(0, -250) # 移动到Y轴下端
    ruler_pen.pendown() # 落笔
    ruler_pen.goto(0, 250) # 绘制Y轴到上端
    
    # 绘制刻度
    for y_coord in range(-200, 201, 50): # 从-200到200,步长为50
        ruler_pen.penup() # 抬笔
        ruler_pen.goto(-10, y_coord) # 移动到刻度线左侧
        ruler_pen.pendown() # 落笔
        ruler_pen.setx(10) # 设置X坐标为10,绘制水平刻度线到右侧
        ruler_pen.penup() # 抬笔
        ruler_pen.goto(-40, y_coord) # 移动到刻度数字左侧
        ruler_pen.write(f"{
           y_coord}", align="right", font=("Arial", 8, "normal")) # 写入刻度数字
    
    my_screen.update() # 手动更新屏幕
    my_screen.exitonclick() # 点击窗口关闭程序
    
    • my_screen.tracer(0): 关闭自动刷新。
    • ruler_pen.hideturtle(): 隐藏海龟。
    • ruler_pen.penup(): 抬笔。
    • ruler_pen.goto(0, -250): 移动到 Y 轴下端点 (0, -250)
    • ruler_pen.pendown(): 落笔。
    • ruler_pen.goto(0, 250): 绘制 Y 轴到 (0, 250)
    • for y_coord in range(-200, 201, 50):: 循环生成从 -200 到 200,步长为 50 的 Y 坐标值。
    • ruler_pen.penup(): 抬笔。
    • ruler_pen.goto(-10, y_coord): 移动到当前 Y 坐标,X 坐标为 -10(刻度线左侧)。
    • ruler_pen.pendown(): 落笔。
    • ruler_pen.setx(10): 核心用法:将海龟的 X 坐标直接设置为 10,Y 坐标保持不变。这将绘制一条从 (-10, y_coord)(10, y_coord) 的水平线段,形成刻度线。
    • ruler_pen.penup(): 抬笔。
    • ruler_pen.goto(-40, y_coord): 移动到刻度数字左侧的位置。
    • ruler_pen.write(f"{y_coord}", ...): 写入当前刻度值。
    • my_screen.update(): 强制刷新屏幕。

3.5 查询当前位置与朝向:pos(), position(), xcor(), ycor(), heading()

了解海龟的当前状态对于调试和进行复杂绘图非常重要。

3.5.1 turtle.pos()turtle.position()
  • 作用:获取海龟当前的X、Y坐标。
  • 参数:无。
  • 返回值:一个包含当前X、Y坐标的Vec2D对象(turtle内部定义的向量类,行为类似于元组)。
  • 示例
    import turtle # 导入turtle模块
    
    my_screen = turtle.Screen() # 创建屏幕对象
    my_screen.title("位置查询") # 设置标题
    
    explorer = turtle.Turtle() # 创建海龟对象
    explorer.shape("arrow") # 设置海龟形状为箭头
    explorer.color("orange") # 设置笔颜色为橙色
    
    # 初始位置
    current_pos = explorer.pos() # 获取海龟当前的位置
    print(f"初始位置: {
           current_pos.x}, {
           current_pos.y}") # 打印海龟的X和Y坐标
    
    explorer.forward(

你可能感兴趣的:(开发语言,python)