你好呀,我是吴老师。
到这里,你的板子已经会亮灯、会画画了。
但它一直有个毛病:它不听你的。
你画了那么多漂亮的东西,可你想让画面变一变 —— 只能改代码、重新装一遍。
今天我教它最后一件事:听你说话。
跟它说话不用嘴,只用一根手指。
读完之后,你应该能:读出手指现在按在屏幕的哪个位置;说清楚"抬手之后坐标会清零"这个坑,并知道怎么绕过它;解释板子怎么分辨"点一下"和"划一下";做出一个能按的按钮;用
gesture认出手势。用时:约 60 分钟。准备:板子、数据线。
看不懂的地方,整段复制给 AI,加一句"请一次只解释一个概念,讲完问我一个小问题"。
一、先问它:手指在哪儿
跟板子要手指的位置,一行就够:
touched, x, y = touch.state()
它一次给你三样东西:
| 拿到什么 | 意思 |
|---|---|
touched | 现在有没有手指按在屏幕上(True / False) |
x、y | 手指按在哪 —— 就是上一课学的那个坐标 |
💡 为什么一次问三个,不分成三次问? 因为它只读一次硬件。你要是分成三次问,万一手指正好在两次之间抬起来, 后面那次就问了个空。一次拿全,最保险。
现在试着做一个「点哪画哪」:
请帮我做一个「点哪画哪」:
手指按在屏幕上时,用一个 ______ 色、半径 ____ 的空心圈跟着手指走;
手指一抬,就在那个位置留下一个 ______ 色、半径 ____ 的实心圆。
屏幕上显示已经画了几个。请用中文注释。
自己把颜色和半径填上。 圈要多大才好看?留下的圆呢?
填不出来?点这里看一个参考(这不是标准答案)
请帮我做一个「点哪画哪」:
手指按在屏幕上时,用一个白色、半径 18 的空心圈跟着手指走;
手指一抬,就在那个位置留下一个黄色、半径 12 的实心圆。
屏幕上显示已经画了几个。请用中文注释。
跑起来是这样(这是点了三下的样子):

二、⚠️ 抬手之后,坐标会清零
现在讲这一课最重要的一件事。很多同学在这儿卡了整整一节课。
假设你想"手指抬起来的时候,在刚才那个位置画一个圆"。
你很自然会这么写:
touched, x, y = touch.state()
if not touched: # 手指抬起来了
screen.fill_circle(x, y, R, 颜色) # ❌ 错!
跑一下 —— 不管点哪儿,圆都画在屏幕左上角。
为什么?
⭐ 因为手指一抬起来,
touch.state()给的坐标就变成(0, 0)了。
不是"记着刚才的位置",是清零 —— 回到原点。
💡 它为什么这么做? 因为"没手指按着"的时候,"手指在哪"这个问题本来就没有答案。 板子很诚实:没有就是没有,给你
(0, 0)。麻烦的是它不报错。你的代码语法是对的、逻辑看着也对, 就是画错地方 —— 这类错误最难查。
正确的做法
在手指还按着的时候,自己把位置记下来。
if touched:
hold = (x, y) # ⭐ 按着的时候记下来
elif pressing:
marks.append(hold) # ⭐ 抬手时用"记下来的那个"
给一个变量专门记着"手指最后待过的地方",抬手时用它。
⭐ 一句话记法: 抬手之后再去问坐标,问到的永远是左上角。 要用,就得在按着的时候先存下来。
三、点一下和划一下,怎么分
现在有第二个问题:手指按下去又抬起来,是"点了一下",还是"划了一下"?
你觉得这还用问吗?对你来说当然一眼就分得出来。但板子不行 —— 它只知道什么时候按下、什么时候抬起、手指经过了哪儿。
板子的办法是:同时看两件事。
| 看什么 | 怎么看 |
|---|---|
| 按了多久 | 按下到抬起,不超过 0.6 秒 |
| 走了多远 | 手指几乎没挪 —— 位移不到 40 个像素 |
两个都满足 → 是"点一下"。 位移超过 40 像素 → 是"划一下"。
💡 为什么要两个一起看?
只看时间:你按住不动停一会儿再抬 —— 时间超了,被当成"划"。可你明明没划。
只看距离:你手抖了一下,手指挪出去几像素 —— 被当成"划"。可你明明只想点。
两个一起看,才分得准。
⚠️ 所以滑的时候要按住再划。 手指刚碰到屏幕就"啪"地弹开的那种划, 板子会当成点一下。这是很多新同学第一次做翻页时会卡的坑(第一课我们提过一次)。
还有双击和长按
板子也帮你想好了:
| 手势 | 怎么算 |
|---|---|
| 单击 | 快按快抬,很快就松手 |
| 双击 | 两下之间隔得不超过 0.26 秒 |
| 长按 | 一直按住,超过 0.8 秒 |
| 滑动 | 手指走超过 40 像素,再分四个方向 |
💡 单击为什么要等一小会儿才出来? 因为它得等一等,看看你会不会点第二下。 不然你每双击一次,会先冒出一个单击 —— 那就乱了。
四、做个能按的按钮
懂了原理,来做实用的东西:三个按钮。

按钮的做法特别朴素:
给每个按钮记住一块矩形范围,手指落下的位置落在哪块里,就算按到了它。
代码里就是一句话的事:看手指的 x、y 有没有落进那个按钮的范围 —— 左边、右边、上边、下边,四个数一比就知道了。
你上一课刚学过 fill_rect(x, y, w, h, 颜色) ——
按钮的范围,就是那块矩形的范围。 画在哪儿、判在哪儿,是同一组数字。
⚠️ 注意判定要写在"刚按下"的那一帧。 不然你手指按着不动,它每一帧都会重新判一次,等于一直重复按。 代码里那个
not was_pressing就是干这个的。
五、手势:不用自己算
看到这儿你可能在想:双击、长按、四方向滑动……这些都要自己算吗?
不用。板子把它们做好了:
import gesture
while True:
gesture.update() # ⭐ 每帧调一次,识别就发生在这里
if gesture.tap(): # 这一帧有单击吗?

一句话就能问它:"刚才有单击吗?""刚才往哪边滑了?"
| 想问什么 | 怎么写 |
|---|---|
| 单击 | gesture.tap() |
| 双击 | gesture.double() |
| 长按 | gesture.long_press() |
| 滑动 | gesture.swipe() → 'left' / 'right' / 'up' / 'down' |
| 还要按着吗 | gesture.pressing() |
| 按了多久 | gesture.held_ms() |
⚠️ 两件事必须记住:
① 每帧都要调
gesture.update()。 识别就发生在那一下,不调它,什么都不会发生。② 事件只在发生的那一帧为真。 这一帧问到了 True,下一帧再问就是 False 了 —— 看到就得立刻用掉,别存起来留着以后用。
那我该用哪个?
| 你要做的 | 用哪个 |
|---|---|
| "点在这块区域里吗"(按钮、棋盘格) | touch.state() —— 你自己比坐标 |
| "他做的是什么手势"(单击、双击、长按、滑动) | gesture —— 现成的 |
💡 一个偷懒的规律: 你能用一块矩形描述清楚"点在哪儿算数" → 用
touch.state(); 你要的是动作本身(他划了一下)→ 用gesture。
六、动手做
动手之前,先回答一个预测题:
如果把手势那个程序里的 gesture.update() 那一行删掉,会发生什么?
想好了再点开
什么手势都认不出来。
屏幕会一直停在你刚打开时的样子 —— 不管你单击、双击、滑来滑去,它都没反应。
因为手势的识别本身就发生在 gesture.update() 里面。
不调它,gesture.tap() 永远返回 False。
⚠️ 而且它不报错 —— 程序跑得好好的,就是不理你。 如果你自己碰到了这种情况,先检查这一行还在不在。
只改一个条件
挑一个来改,先说出你的预测,再动手:
| 我改的条件 | 我预测会怎样 | 实际怎样 |
|---|---|---|
把「点哪画哪」里的 R = 12 改成 R = 30 | ||
按钮那个程序,把 not was_pressing 去掉 | ||
把按钮的 BTN_H = 56 改成 BTN_H = 20 | ||
把 gesture 的 LONG_MS 从 800 改成 300 | ||
「点哪画哪」里,把 hold 换成抬手时的 x, y |
最后一行是今天的重点考题。 它改的就是第二节讲的那个坑 —— 改完试试看,圆会画到哪儿去。
七、自检小测
八、还想玩点什么
| 方向 | 可以描述给 AI 的效果 | 值得继续想 |
|---|---|---|
| 颜色开关 | 点一下屏幕,背景换一种颜色 | 怎么让它"轮流"换,而不是乱换? |
| 四方向摇杆 | 上滑加速、下滑减速、左右转方向 | 怎么把"手势"变成"一直持续的状态"? |
| 涂鸦板 | 手指划过去,留下一串点 | 上一课学的"只擦改过的地方"在这儿用得上吗? |
| 你画我猜 | 一个人画,另一个人猜 | 画的东西怎么传给对方的板子? |
最后一行的题我留给你慢慢想 —— 它牵着一个很大的问题: 两块板子,怎么互相说话?
这一课的作品,就在上面那几张卡片里 —— 点「装到板子上」,用 USB 线或者蓝牙选你的板子,几秒就装好了。 装完板子会自己打开它,不用按任何按键,也不用去桌面上翻页找。
想看它是怎么写出来的,点卡片上的「查看源码」。