# 教案：第22节 —— 综合项目二（画图编辑器）

---

## 元信息

| 项目 | 内容 |
|------|------|
| **课程编号** | G2_第22节 |
| **GESP等级** | **二级**（GESP Python 二级考点） |
| **适用年龄** | 9-11 岁（编程进阶阶段） |
| **核心知识点** | turtle 绘图指令、EasyGUI 图形界面、函数模块化设计、三层挑战结构 |
| **记忆钩子** | "turtle 画画 easygui 选菜单 函数拆模块 三层挑战通关" |
| **身体锚点** | ① 选工具（举手选择） ② 点画布（手指点画） ③ 存文件（握拳保存） |

---

## 课程目标

1. **掌握** turtle 的事件驱动绘图：点击画点、拖动画线
2. **使用** EasyGUI 创建菜单交互：工具选择、颜色选择、大小调整
3. **理解** 函数式编程思想：功能模块化、参数化设计
4. **完成** 三层挑战：基本画图、添加选项、保存作品

---

## 项目概述

本课通过一个完整的画图编辑器项目，综合运用前面学过的所有知识。

**三层挑战结构：**

| 关卡 | 难度 | 内容 | 知识点 |
|------|------|------|--------|
| 第一关 | ★☆☆☆☆ | 基本画图 | turtle 基础指令、事件绑定 |
| 第二关 | ★★☆☆☆ | 添加选项 | EasyGUI 菜单、函数模块化 |
| 第三关 | ★★★☆☆ | 保存作品 | 文件保存、错误处理、完整流程 |

---

## 五段式 60 分钟教学流程

---

### 第一段：导入（00:00 - 10:00）—— "我们要造一个画图软件"

#### 教师活动

| 时间 | 活动内容 | 教学方式 |
|------|---------|---------|
| 0-3min | 展示画图程序，问："想不想自己写一个？" | 展示吸引 |
| 3-6min | "用 Python 的 turtle + EasyGUI 来造一个画图编辑器！" | 目标宣布 |
| 6-10min | 快速演示最终效果（运行第三关的完整程序） | 成果预览 |

#### 导入对话

> 教师："你们用过的画图软件，点击按钮就能画圆、画方、换颜色——背后是什么？"
> 学生："……"
> 教师："就是 turtle！加上菜单和按钮来选工具。"
> 教师："今天我们分三关，一关一关做出来！"

#### 身体锚点

> **【身体锚点 — 画图编辑器】**
> 第一关：伸出食指做"画笔"手势，在空中画圆。
> 第二关：另一只手做"菜单"手势，假装在选颜色。
> 第三关：双手做"保存"动作，放在胸前。

---

### 第二段：知识点精讲（10:00 - 30:00）

#### 2.1 turtle 事件驱动绘图（8min）

**核心概念：事件驱动**

```python
import turtle

def draw_circle(x, y):
    t.penup()
    t.goto(x, y)
    t.pendown()
    t.circle(30)

t = turtle.Turtle()
screen = turtle.Screen()
screen.onscreenclick(draw_circle)
screen.mainloop()
```

**关键概念讲解：**

| 概念 | 说明 | 比喻 |
|------|------|------|
| 事件 | 用户的操作（点击、按键） | 有人敲门 |
| 回调函数 | 事件发生时执行的函数 | 开门这个动作 |
| 事件绑定 | 把事件和函数连起来 | 设定敲门就去开门 |
| 事件循环 | 持续等待事件的循环 | 一直在家等人敲门 |

#### 2.2 EasyGUI 菜单交互（7min）

```python
import easygui

tool = easygui.choicebox(
    "请选择绘图工具", "工具选择",
    ["画笔", "圆形", "矩形", "星形", "三角形"]
)

answer = easygui.buttonbox("确认?", "确认", ["确定", "取消"])

size = easygui.integerbox(
    "画笔粗细（1-10）", "画笔设置",
    default=3, lowerbound=1, upperbound=10
)

file_path = easygui.filesavebox("保存作品", default="my_drawing.eps")
easygui.msgbox("作品已保存！", "成功")
```

**EasyGUI 函数总结：**

| 函数 | 用途 |
|------|------|
| choicebox() | 从列表中选择一项 |
| buttonbox() | 点击按钮确认 |
| integerbox() | 输入整数 |
| filesavebox() | 选择保存路径 |
| msgbox() | 显示提示信息 |

#### 2.3 函数模块化设计（5min）

**为什么要拆成函数？**

```python
def setup_screen():
    screen = turtle.Screen()
    screen.title("画图编辑器")
    screen.setup(800, 600)
    return screen

def setup_pen():
    pen = turtle.Turtle()
    pen.speed(5)
    pen.pensize(3)
    return pen

def draw_circle(x, y):
    pen.penup()
    pen.goto(x, y)
    pen.pendown()
    pen.circle(30)

screen = setup_screen()
pen = setup_pen()
screen.onscreenclick(draw_circle)
screen.mainloop()
```

**函数模块化的好处：**
1. 代码更清晰——每个函数只做一件事
2. 容易修改——改一个功能只需改一个函数
3. 容易扩展——加新功能只需加新函数
4. 可以复用——函数可以在其他地方再用

#### 2.4 画布保存原理（3min）

```python
canvas = screen.getcanvas()
canvas.postscript(file="作品.eps")
print("已保存到 作品.eps")
```

---

### 第三段：演示（30:00 - 40:00）

#### 演示 1：第一关——基本画图

```python
import turtle

screen = turtle.Screen()
screen.title("画图编辑器 - 第一关")
screen.setup(800, 600)
screen.setworldcoordinates(-400, -300, 400, 300)

pen = turtle.Turtle()
pen.speed(8)
pen.pensize(3)
pen.color("blue")

def draw_at_click(x, y):
    pen.penup()
    pen.goto(x, y)
    pen.pendown()

screen.onscreenclick(draw_at_click)
screen.mainloop()
```

**演示要点：** 点击屏幕任意位置，乌龟移动到点击位置画线。

#### 演示 2：第二关——添加选项

```python
import turtle
import easygui

config = {"tool": "画笔", "color": "black", "size": 3}

def choose_tool():
    tools = ["画笔", "圆形", "矩形", "星形", "三角形"]
    config["tool"] = easygui.choicebox("选择工具", "工具", tools)

def choose_color():
    colors = ["red", "blue", "green", "orange", "purple", "black"]
    names = ["红色", "蓝色", "绿色", "橙色", "紫色", "黑色"]
    choice = easygui.choicebox("选择颜色", "颜色", names)
    if choice:
        idx = names.index(choice)
        config["color"] = colors[idx]
        pen.pencolor(config["color"])
```

#### 演示 3：第三关——保存作品

```python
import os

def save_drawing():
    fp = easygui.filesavebox("保存作品", default="my_drawing.eps")
    if fp:
        canvas = screen.getcanvas()
        canvas.postscript(file=fp)
        easygui.msgbox(f"已保存: {fp}", "成功")
```

**三层对比总结：**

| 功能 | 第一关 | 第二关 | 第三关 |
|------|--------|--------|--------|
| 画图 | 点击画线 | 多种图形 | 多种图形 |
| 菜单 | 无 | EasyGUI 菜单 | EasyGUI 菜单 |
| 颜色 | 固定蓝色 | 可选颜色 | 可选颜色 |
| 粗细 | 固定 | 可选 | 可选 |
| 保存 | 无 | 无 | EPS 保存 |
| 清空 | 无 | 无 | 清空画布 |
| 退出确认 | 无 | 无 | 退出确认 |

---

### 第四段：实操练习（40:00 - 55:00）

#### 练习 1：实现点击画点（5min）

```
题目：补全代码，让 turtle 在点击位置画一个半径为 20 的圆点
提示：使用 dot() 或 circle()
```

**参考答案：**
```python
import turtle

def draw_dot(x, y):
    t.penup()
    t.goto(x, y)
    t.pendown()
    t.dot(20)

t = turtle.Turtle()
screen = turtle.Screen()
screen.onscreenclick(draw_dot)
screen.mainloop()
```

#### 练习 2：添加工具选择菜单（5min）

```
题目：使用 EasyGUI 让用户选择"画笔"或"橡皮擦"
提示：使用 choicebox()
```

**参考答案：**
```python
import easygui

tools = ["画笔", "橡皮擦"]
choice = easygui.choicebox("请选择工具", "工具选择", tools)
if choice == "橡皮擦":
    pen.pencolor("white")
    pen.pensize(20)
else:
    pen.pencolor("black")
    pen.pensize(3)
```

#### 练习 3：实现画矩形功能（5min）

```
题目：补全代码，在点击位置画一个矩形
提示：矩形需要四个边，用 for 循环
```

**参考答案：**
```python
def draw_rect(x, y):
    pen.penup()
    pen.goto(x, y)
    pen.pendown()
    for i in range(2):
        pen.forward(60)
        pen.right(90)
        pen.forward(40)
        pen.right(90)
```

---

### 第五段：小测（55:00 - 60:00）

#### 题目 1（选择）
turtle 中绑定鼠标点击事件的函数是？
A. turtle.click()
B. screen.onscreenclick()
C. screen.onclick()
D. turtle.bind()

**答案：B**

#### 题目 2（选择）
EasyGUI 中让用户从列表选择一项的函数是？
A. msgbox()
B. choicebox()
C. integerbox()
D. filesavebox()

**答案：B**

#### 题目 3（选择）
将 turtle 画布保存为文件的代码是？
A. turtle.save("file.eps")
B. screen.save("file.eps")
C. canvas.postscript(file="file.eps")
D. turtle.export("file.eps")

**答案：C**

#### 题目 4（判断）
函数模块化的好处包括代码更清晰、容易修改、容易扩展。

**答案：** 对

#### 题目 5（简答）
为什么第三关比第一关需要更多的代码？

**答案：** 第三关增加了菜单交互、颜色选择、粗细调整、文件保存、清空画布、退出确认等功能。

---

## 板书设计

```
+-------------------------------------------------------+
|       第22节 综合项目二 --- 画图编辑器                  |
+-------------------------------------------------------+

  三层挑战：
  第一关 基本画图      点击画线
  第二关 添加选项  EasyGUI 菜单
  第三关 保存作品   文件保存

  事件驱动流程：
  启动 -> 等待点击 -> 执行回调 -> 继续等待

  函数模块化：
  setup_screen()   setup_pen()
  choose_tool()    choose_color()
  draw_shape()     save_drawing()

  记忆钩子：
  "turtle 画画 easygui 选菜单 函数拆模块 三层通关"
---

## 课后延伸

| 项目 | 内容 |
|------|------|
| 课后练习 | 课后练习_第22节.md |
| 预习内容 | 第22节 字符串进阶 |
| 拓展挑战 | 添加"撤销"和"文字工具"功能 |
| 家长沟通 | 今天孩子完成了一个画图编辑器项目 |

---

## 教学反思

| 维度 | 记录 |
|------|------|
| 学生掌握率 | 预计 70% 完成第二关，50% 完成第三关 |
| 常见困惑 | 事件驱动概念抽象，需反复演示流程 |
| 改进方向 | 准备第三关的完整代码备份 |
| 备注 | 综合项目课，建议适当放宽时间 |
```
