1. 从零开始:为什么用Python Turtle画窗花?

几年前,我刚开始教孩子编程,想找个既有趣又有文化内涵的项目。当时就想到了窗花——那种贴在窗户上,红彤彤、线条繁复又充满吉祥寓意的剪纸艺术。用代码“剪”窗花?听起来就很有意思。试了一圈,发现Python自带的turtle模块简直是绝配。它就像一支无形的笔,你告诉它“往前走100步”、“左转45度”,它就能在屏幕上画出线条。这种命令式的绘图方式,和剪纸时“沿着这条线剪”、“在这里转个弯”的思考过程非常像。

对于编程新手或者对传统文化感兴趣的朋友来说,用turtle画窗花是个完美的入门项目。你不需要理解复杂的图形学算法,也不用被各种绘图库的API搞得头晕。你只需要有最基础的Python语法知识(比如循环、函数),再加上一点点的几何和耐心,就能创造出属于自己的数字窗花。这个过程本身,就是一种“慢编程”的享受。看着海龟画笔一笔一划地勾勒出对称、精美的图案,那种成就感,和亲手剪出一张窗花没什么两样。

更重要的是,这不仅仅是编程练习。窗花的图案里,藏着很多老祖宗的智慧:对称、循环、中心放射……这些美学原则和数学规律,在代码里会体现得淋漓尽致。当你用for循环画出八个一模一样的花瓣时,你就在实践“重复产生美”。当你通过计算坐标来确保图案严丝合缝时,你就在理解几何的精确。所以,别把这当成一个枯燥的代码练习,把它看作一次跨越数字与传统的创作之旅吧。

2. 环境准备与Turtle核心操作速成

工欲善其事,必先利其器。好消息是,你几乎不需要准备什么。只要你电脑上安装了Python(建议3.6以上版本),turtle模块就已经在里面了,它是Python标准库的一部分。你不需要运行pip install去额外安装它(这点和很多第三方库不同)。你可以直接打开你喜欢的代码编辑器,比如VS Code、PyCharm,或者哪怕是最简单的IDLE,新建一个.py文件,就可以开始了。

让我先带你快速过一遍turtle最常用、画窗花绝对离不开的几个核心命令。你可以把这些命令想象成指挥画笔的“咒语”。

移动与绘画

  • forward(distance)fd(distance):让海龟向前移动指定距离,如果画笔落下,就会画出一条线。
  • backward(distance):向后移动。
  • right(angle)rt(angle):海龟向右转(顺时针)某个角度。
  • left(angle)lt(angle):向左转(逆时针)。
  • goto(x, y):让海龟瞬间移动到画布的指定坐标位置。这是精准定位的神器。
  • setheading(angle)seth(angle):直接设置海龟的朝向(0度是向东,90度向北,以此类推)。

画笔控制

  • penup()pu():抬起画笔。移动时不画线,用于移动到新的起点。
  • pendown()pd():落下画笔。准备开始画。
  • pensize(width):设置画笔的粗细。画窗花轮廓和内部纹路时,粗细变化能让图案更有层次。
  • pencolor(color_string):设置画笔颜色。窗花当然主打红色,你可以用 "red", "#FF0000",或者尝试 "darkred"(深红)也不错。
  • speed(speed):设置海龟移动速度,从1(最慢)到10(最快),0是瞬间完成。调试时用慢速,看清楚了再调快。

窗口与状态

  • setup(width, height):设置绘图窗口的大小。
  • hideturtle():把海龟图标隐藏起来,让画面更干净。
  • done():告诉程序绘图结束了,它会保持窗口打开,直到你手动关闭。

这里有个小技巧,我习惯在代码开头写一个goto(x, y)的辅助函数,因为画复杂图案时,频繁的penup()pendown()很麻烦。像这样:

import turtle

def goto(x, y):
    turtle.penup()
    turtle.goto(x, y)
    turtle.pendown()

# 之后就可以直接用 goto(100, 100) 来移动并准备画了

掌握了这些,你的“数字剪刀”就已经握在手里了。接下来,我们就要研究窗花图案的“刀法”了。

3. 解构窗花:从简单几何到复杂图案

在动笔(码)之前,咱们得先当好“设计师”,把要画的窗花拆解明白。窗花看起来复杂,但很多都是由最基本的几何图形,通过对称重复组合而成的。咱们由易到难,一步步来。

3.1 核心之美:对称与旋转

对称是窗花的灵魂。最常见的是中心对称(旋转对称)和轴对称。用turtle实现旋转对称特别简单,秘诀就是画好一个“基本单元”,然后让海龟旋转一定角度,重复画这个单元。

比如,我们来画一个最简单的八瓣团花。你可以把它想象成8个完全相同的花瓣,围绕一个中心点均匀排列。

import turtle

turtle.speed(5)
turtle.pencolor("red")
turtle.pensize(3)

for _ in range(8):  # 重复8次
    turtle.forward(100)  # 画一个花瓣的“茎”
    turtle.dot(20, "red") # 在末端画个圆点当作花蕊(可选)
    turtle.backward(100)  # 退回中心点
    turtle.right(45)      # 旋转45度(360/8=45)

运行这段代码,你会看到8条线从中心放射出去。这就是旋转对称最基础的形态。你可以把forwardbackward的部分,替换成更复杂的图形,比如画个弧形花瓣,一个复杂的单元就诞生了。

3.2 基础模块:绘制常见窗花元素

复杂的窗花是由许多小元素构成的。我们来封装几个常用的“笔画”函数:

  • 菱形:窗花里超级常见的元素。

    def draw_diamond(size):
        """画一个菱形"""
        for _ in range(2):
            turtle.forward(size)
            turtle.right(60)   # 锐角菱形的内角设为60度和120度
            turtle.forward(size)
            turtle.right(120)
    
  • 铜钱纹(方孔圆钱):象征财富,由正方形和圆组成。

    def draw_coin(radius):
        """画一个铜钱纹"""
        # 先画外圆
        turtle.circle(radius)
        # 移动到方孔位置,画正方形
        turtle.penup()
        turtle.forward(radius/3) # 假设方孔边长为半径的1/3
        turtle.left(90)
        turtle.forward(radius/3)
        turtle.right(90)
        turtle.pendown()
        for _ in range(4):
            turtle.forward(radius/1.5) # 边长
            turtle.right(90)
    
  • 月牙纹(弧形):用circle命令配合角度控制就能画。

    def draw_crescent(radius, angle):
        """画一段月牙/弧形,radius为半径,angle为弧度角度"""
        turtle.circle(radius, angle)
    

3.3 设计你的第一个窗花图案

现在,我们把对称和基础元素结合起来。设计一个“四角菱花”图案:中心一个旋转的菱形组,四角配以小的铜钱纹。

思路步骤:

  1. 定中心:将画布中心设为(0,0)。
  2. 画中心花:用一个循环画4个旋转的菱形,形成中心团花。
  3. 移向四角:用goto()函数将海龟移动到画布的四个角附近。
  4. 画角花:在每个角调用draw_coin()函数画一个小铜钱纹。
  5. 勾边:最后用粗一点的画笔,画一个大的正方形边框,把整个图案框起来。

这个设计过程,就是编程思维和艺术设计的结合:分解问题(拆解图案) -> 抽象模式(发现对称和重复) -> 自动化(用循环和函数实现) -> 组合优化(调整位置和参数)。多试几次,你会发现自己开始能用“代码思维”去观察生活中的传统图案了。

4. 实战:分步绘制一个完整的“福字团花”

光说不练假把式。咱们来真刀真枪地画一个稍微复杂点,但寓意很好的窗花——一个围绕“福”字的团花。这个图案包含了中心文字、环绕的装饰花纹和最外圈的边框,层次比较丰富。

4.1 第一步:搭建绘图框架与绘制外框

任何复杂的绘图,一个好的开头都是设置好画布和画笔。我们这次用深红色,并且把速度调慢一点,方便观察。

import turtle

# 1. 初始化设置
turtle.setup(900, 900)  # 窗口大小
turtle.bgcolor("#FFF8DC")  # 设置一个淡黄色的背景,更像宣纸
turtle.title("福字团花")
turtle.pensize(4)
turtle.pencolor("darkred")
turtle.speed(8)  # 速度适中

# 我们的辅助移动函数
def goto(x, y):
    turtle.penup()
    turtle.goto(x, y)
    turtle.pendown()

# 2. 绘制最外层的方形边框
# 我们先画一个粗重的红框,定下整个作品的基调
turtle.pensize(8)
goto(-300, 300)  # 移动到左上角起点
for _ in range(4):
    turtle.forward(600)  # 边长600
    turtle.right(90)
turtle.pensize(4)  # 画完边框后改回普通粗细

这一步完成后,你应该能看到画布中央有一个醒目的红色大方框。这就是我们作品的“舞台”。

4.2 第二步:绘制环绕的装饰花纹

现在,在边框和内层“福”字之间,我们要画一圈连续的、旋转的装饰花纹。这里我们设计成由许多个“小月牙”首尾相连组成的环。

# 3. 绘制环绕花纹
# 我们让海龟沿着一个看不见的圆路径,每隔一段距离画一个方向交替的月牙
goto(0, 200)  # 移动到中心点上方200像素的位置,作为装饰环的起点
turtle.setheading(0)  # 头朝东

ring_radius = 180  # 装饰环的半径
deco_count = 16     # 装饰花纹的数量

for i in range(deco_count):
    # 计算当前要画月牙的位置(沿着圆周)
    angle = i * (360 / deco_count)
    radian = math.radians(angle)
    x = ring_radius * math.cos(radian)
    y = ring_radius * math.sin(radian) + 50  # +50是为了让环在垂直方向上居中一些
    
    goto(x, y)
    
    # 调整海龟朝向,使其指向圆心
    turtle.setheading(angle + 180)
    
    # 画一个月牙纹。通过控制circle的半径和角度,可以画出不同弧度的月牙
    # 这里画一个半圆少一点的弧,更像花瓣
    if i % 2 == 0:  # 奇偶交替改变弯曲方向,产生动感
        turtle.circle(30, 120)  # 半径为30,画120度的弧
    else:
        turtle.circle(-30, 120)

这段代码稍微有点绕,核心思想是极坐标转换。我们通过math库的sincos函数,把圆上的角度(angle)转换成具体的屏幕坐标(x, y)。turtle.setheading(angle + 180)这句很关键,它让海龟的“鼻子”指向圆心,这样画出来的月牙纹才是向心环绕的。i % 2的判断让相邻的月牙一正一反,图案立刻就活泼起来了。

4.3 第三步:在中心位置书写“福”字

窗花的中心,往往是一个吉祥字,“福”字是最经典的。我们用turtle的写字功能来实现。

# 4. 书写中心“福”字
goto(-70, 0)  # 移动到中心偏左上的位置,准备写字
turtle.pencolor("gold")  # 用金色来写福字,更喜庆
turtle.pensize(1)  # 写字时用细笔

# 使用turtle的write函数,可以指定字体、大小
# 注意:系统中需要存在相应的中文字体,这里用常见的“楷体”
try:
    turtle.write("福", align="center", font=("楷体", 120, "bold"))
except:
    # 如果楷体不存在,回退到默认字体
    turtle.write("福", align="center", font=("Arial", 120, "bold"))

turtle.pencolor("darkred")  # 写完字把颜色改回来
turtle.pensize(4)

这里有个实际开发中常遇到的坑:中文字体turtle.write()依赖你操作系统里的字体。在Windows上,“楷体”、“黑体”一般没问题。但在Mac或某些Linux系统上,可能需要指定其他已安装的中文字体名,或者使用字体文件路径。如果运行时报错找不到字体,可以尝试换成“SimHei”(黑体)或“STKaiti”(苹果楷体)。

4.4 第四步:添加内部点缀与细节完善

一个生动的图案离不开细节。我们在“福”字和装饰环之间的空白处,加一些散点的小菱形,作为点缀。

# 5. 添加内部点缀小菱形
def draw_small_diamond():
    """画一个小菱形点缀"""
    side = 15
    turtle.begin_fill()  # 开始填充
    for _ in range(2):
        turtle.forward(side)
        turtle.right(60)
        turtle.forward(side)
        turtle.right(120)
    turtle.end_fill()

# 在四个角的方向上添加小菱形
goto(-100, 100)
turtle.setheading(45)  # 朝向东北
draw_small_diamond()

goto(100, 100)
turtle.setheading(135) # 朝向西北
draw_small_diamond()

goto(100, -100)
turtle.setheading(225) # 朝向西南
draw_small_diamond()

goto(-100, -100)
turtle.setheading(315) # 朝向东南
draw_small_diamond()

# 最后,隐藏海龟,完成绘制
turtle.hideturtle()
turtle.done()

注意看draw_small_diamond函数里,我用到了begin_fill()end_fill()。这对命令可以让海龟在画完一个封闭图形后,自动用当前颜色(可以用fillcolor()设置)填充内部。这里我们没设fillcolor,所以默认用画笔颜色(darkred)填充,画出了实心的小菱形,比空心线条更有质感。

把上面所有代码段按顺序组合在一起,运行它。你会看到一个金色的“福”字居于中央,被一圈深红色的旋转月牙纹环绕,四角点缀着菱形,最外面是厚重的红色边框。一个由代码生成的、充满传统韵味的窗花图案就缓缓呈现在屏幕上了。你可以尝试调整颜色(比如把装饰环改成金色,福字用红色)、改变装饰花纹的数量和形状,或者把“福”字换成其他吉祥字,比如“春”、“寿”,创造出属于你自己的独特窗花。

5. 创意进阶:让窗花动起来与导出分享

画出一个静态图案已经很有成就感了,但turtle的乐趣不止于此。我们可以让窗花的绘制过程本身变成一场动画,或者把作品保存下来分享给朋友。

5.1 制作绘制过程动画

turtlespeed()函数虽然能控制快慢,但想要更炫酷的逐笔绘制效果,我们可以利用tracer()update()函数。tracer(0)可以关闭动画缓冲,让海龟的动作不会实时显示在屏幕上;然后我们手动控制,每画完一小部分,就调用一次update()来更新屏幕。这样就能实现“一笔一划”慢慢呈现的效果。

比如,在我们画装饰环的循环里,可以这样改:

turtle.tracer(0)  # 在代码最开头,初始化后立刻关闭自动刷新

# ... 其他的初始化代码 ...

# 在绘制装饰环的循环内部
for i in range(deco_count):
    # ... 计算坐标和画月牙的代码 ...
    if i % 2 == 0:
        turtle.circle(30, 120)
    else:
        turtle.circle(-30, 120)
    
    turtle.update()  # 每画完一个月牙,就更新一次屏幕
    time.sleep(0.2)  # 暂停0.2秒,让观众看清

turtle.tracer(1)  # 绘制完成后,重新打开自动刷新(如果需要)

记得在文件开头import time。这样运行,你会看到月牙纹一个接一个地“生长”出来,非常有仪式感。你可以把这个技巧用在绘制边框、中心字等任何步骤上。

5.2 导出为图片文件

辛辛苦苦画的窗花,关掉窗口就没了岂不可惜?turtle模块提供了将画布保存为图片的功能,主要是PostScript (.eps) 矢量图格式,或者通过其他库转换为PNG等。

最简单的方法是使用turtlegetcanvas()方法:

# 在全部绘制完成,turtle.done()之前,添加以下代码
canvas = turtle.getscreen().getcanvas()
canvas.postscript(file="my_window_flower.eps", colormode='color')  # 保存为EPS文件
print("窗花已保存为 my_window_flower.eps")

EPS是矢量图,可以无限放大不失真,非常适合打印。如果你想得到更通用的PNG或JPG图片,可以安装Pillow库(PIL的一个分支)来进行转换。虽然多一步,但分享到社交媒体会更方便。

5.3 挑战更复杂的图案:冰裂纹与套色

当你掌握了基本技巧,就可以挑战更复杂的传统窗格样式,比如“冰裂纹”。这种图案由许多不规则的多边形拼接而成,看似随机,实则有序。实现思路可以是:先画一个大的多边形外框,然后用随机(但受控)的线段将其内部分割成多个小多边形。这需要用到一些随机数生成和几何计算,是很好的算法练习。

另一个方向是“套色窗花”,即多种颜色的窗花叠加。传统的套色剪纸是用不同颜色的纸刻好后拼贴的。在turtle里,我们可以通过分层绘制来实现:先画底层最大的红色轮廓,然后换一种颜色(比如金色)画中间层的花纹,最后用第三种颜色画最精细的细节。关键在于精确计算每一层图案的起始位置,让它们能完美对齐。这对手工剪纸来说是高难度技巧,但对编程来说,只要坐标算得准,实现起来反而很规整。

画窗花这件事,我带着孩子和学生们做过很多次。最开始大家都会盯着坐标和角度算得头晕,但一旦第一个对称图案成功运行起来,那种“哇!”的惊喜是共通的。有个学生后来甚至用这个思路,为他家乡的旅游景点设计了一套数字窗花明信片。代码不只是冰冷的逻辑,当它和温度深厚的传统文化结合,就能创造出独特的美。你的鼠标和键盘,就是新时代的剪刀和红纸。别怕试错,多调调颜色,改改参数,甚至“破坏”一下对称看看效果。最有趣的图案,往往诞生于某次意外的bug之后。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐