Thonny去图标与ESP32-S3 MicroPython教学环境批量定制
Thonny 这个 IDE 我用得算久了从最早带零基础的人入门 Python到后来拿它当 ESP32-S3 跑 MicroPython 的主力编辑器它一直属于装完就能干活的那一类工具。但装完就能干活和装完就完全符合我的交付要求是两回事。上个月给一间实训室做统一环境交付Thonny 装完第一件事就是处理界面里那个内置的旗帜图标——一张和功能完全无关的装饰性贴图出现在关于对话框里。实训机的要求是界面元素尽量干净学生打开软件看到的每一像素都应该和写代码有关。所以我花了点时间把 Thonny 的资源目录翻了一遍把去掉这个图标的几种做法都试了一轮顺手也把批量部署和 ESP32 教学环境的配置一起理顺了。这篇就把整个过程拆开讲清楚包括为什么有些改法看着省事却一定会翻车、升级之后怎么不让改动被冲掉、以及同一套思路怎么顺带用在 MicroPython 环境的统一定制上。1. 先把去掉图标这件事拆成能执行的动作很多人遇到这类需求第一反应是打开安装目录找到一个 png 删掉重启软件发现没变化或者直接报错然后就卡住了。问题不在于手速而在于一开始没有判断这张图到底是文件资源还是代码里内嵌的数据也没有想清楚这次改动是要一次性的还是要能反复执行的。这两点判断错了后面每一步都会走偏。1.1 要动的到底是哪一层东西Thonny 的界面是用 Python 加 tkinter 写的这一点很关键。tkinter 加载图片的典型方式是tkinter.PhotoImage(file某个路径)也就是说界面上看到的绝大多数图标、贴图本质上是磁盘上一个真实的图片文件运行时被读进内存。这意味着两件事第一改文件是可行的第二如果文件被删掉而代码还在尝试加载它Tcl 层会直接抛TclError: couldnt open ...软件可能在启动或者点开对话框的瞬间崩给你看。另一个可能性是图片根本没有独立文件而是被转成 base64 字符串写死在.py里再用tkinter.PhotoImage(data...)加载。这种情况删文件是没用的必须动源码。判断方法很简单先在资源目录里找有没有对应的图片文件再去源码里搜这个文件名的引用。如果两处都找不到才需要往 base64 方向查。所以整个动作链其实是三步定位资源 → 判断类型 → 选择改法。跳过第一步直接改等于闭着眼睛修车。1.2 三种场景对应的改法完全不同同一个去掉图标的需求放在不同场景下成本差好几倍。我在实训室、个人笔记本、以及给朋友做的内部打包版这三种环境里各走了一遍感受非常明显场景影响面推荐改法后续维护成本个人单机自用1 台机器直接替换资源文件升级后手动重做一次可接受实训室/机房批量几十台机器替换文件 脚本化 配置一起下发低脚本可重复执行做成内部发行版长期多处使用fork 源码改完重新打包前期高后期最低单机自用其实是最简单的改完就完事。真正的坑在批量场景你今天改完十台明天有人手抖点了升级图标全回来了而且因为文件被覆盖你甚至不容易发现。发行版场景则要考虑源码怎么改得干净、不破坏原有的资源加载逻辑。我的建议是只要涉及两台以上机器就一定要把改动写成脚本而不是靠手动操作记录。这个习惯在后面会反复救你。2. 定位资源从关于对话框反查到具体文件这一步是整个流程里最像侦探工作的部分也是最值得花时间的部分。找对了文件后面十分钟就结束了找错了你可能改一个下午都在改一个根本没被加载的副本。2.1 先确认你的 Thonny 装在哪不同安装方式目录结构差别很大先确认清楚再动手pip / pipx 安装包在 Python 环境的site-packages/thonny下跟着虚拟环境走。官方 Windows 安装包通常落在%LOCALAPPDATA%\Programs\Thonny包体在Lib\site-packages\thonny有些版本或安装选项会装到Program Files下那里默认只读。Linux 发行版仓库装一般在/usr/lib/python3/dist-packages/thonny或/usr/lib/python3.*/site-packages/thonny。macOS 应用包在.app里需要右键显示包内容才能进去。最省事的确认方式不是去猜路径而是让 Python 自己告诉你python -c import thonny, os; print(os.path.dirname(thonny.__file__))如果你平时用的是 Thonny 自带的解释器而不是系统 Python记得在 Thonny 的 Shell 里跑这一句才能拿到它自己实际加载的那个包路径。这一步经常被忽略结果是在系统 Python 的目录里改了半天而 Thonny 用的是另一份拷贝。2.2 一段脚本把所有图片资源列出来拿到包目录之后不要手动一层层点。直接扫一遍所有图片文件按大小排序通常一眼就能锁定目标import os import thonny root os.path.dirname(thonny.__file__) for dirpath, dirnames, filenames in os.walk(root): for fn in filenames: if fn.lower().endswith((.png, .gif, .jpg, .jpeg, .ico, .bmp, .ppm, .xbm)): p os.path.join(dirpath, fn) print(f{os.path.getsize(p):8} {os.path.relpath(p, root)})输出里那些几百字节到几 KB 的小图基本都是按钮图标关于对话框里那张尺寸明显大一圈的旗帜贴图通常会是列表里比较扎眼的一个。资源一般集中在thonny/res这个目录下但也有些版本会把图标分散到插件目录里所以用遍历而不是用ls是更稳的做法。拿到候选之后最直接的验证方法是把文件临时改个名然后打开 Thonny 点开关于对话框看是报错、留白还是完全没变化。这个对照实验能一次性告诉你三件事文件是不是真的被用、代码有没有容错、以及布局会不会塌。2.3 在源码里搜引用确认是文件还是内嵌Windows 上用 PowerShellGet-ChildItem -Path $env:THONNY_ROOT -Recurse -Include *.py | Select-String -Pattern PhotoImage|\.png|\.gif|base64Linux / macOS 上更快grep -rn --include*.py -E PhotoImage|\.png|\.gif|base64 $(python -c import thonny,os;print(os.path.dirname(thonny.__file__)))重点看两类结果一类是file资源路径说明是外部文件替换文件即可另一类是data长字符串说明是内嵌数据必须改代码。还有一种中间情况是资源路径由变量拼接而成比如os.path.join(get_workbench().get_localized_... )这种就得顺着变量往上追一层。提示搜索时不要只搜旗帜这个词搜加载图片的 API 名字命中率更高关于对话框的具体实现模块名各版本有差异按 API 搜比按语义搜靠谱。3. 替换、删除还是打补丁三种做法的真实成本这是最容易想当然的地方。我一开始也以为删掉就完了实测下来删文件是最容易翻车的方案没有之一。3.1 为什么直接删文件最容易出事tkinter 的PhotoImage在文件不存在时不会安静地返回一张空图它会把 Tcl 层的错误直接抛到 Python也就是TclError。如果这个加载过程发生在窗口初始化阶段结果就是对话框打不开甚至整个界面起不来如果发生在回调里就是点一下崩一下。更麻烦的是这类异常往往只在打开特定对话框时才触发日常敲代码完全正常等到你在实训室里演示的时候才炸现场非常尴尬。正确做法是用一张同样尺寸的透明 PNG 覆盖原文件而不是删掉它。这样代码照样能加载成功只是画出来什么都看不见布局也不会因为缺图而塌掉。这个思路在资源定制里是通用套路能替换就不要删除。3.2 什么时候必须动源码有三种情况替换文件解决不了第一图片是 base64 内嵌的磁盘上没有对应文件。这种情况必须找到构造PhotoImage的那一行把 data 换成一张透明图的 base64。第二代码里对图片尺寸有硬编码依赖比如布局按图片宽度算坐标你换了一张不同尺寸的图对话框排版就歪了。这种情况下替换时要严格保证宽高一致或者干脆改源码里那段布局逻辑。第三图片来源被简化到只剩一个明显的留白视觉上比原来更难看。这时候与其纠结替换尺寸不如把那段创建图片并pack的代码整段去掉反而更干净。3.3 三种方案对比方案操作难度抗升级风险适用场景直接替换资源文件低差升级即失效低有备份时单机自用替换文件 补丁脚本中中升级后重跑脚本低机房批量改源码重新打包高好中需回归测试内部发行版补丁脚本方案是我最推荐的折中成本可控而且升级后重跑一次这个动作本身就是一种保障你能明确知道当前机器的状态是不是你想要的。4. 实操十几分钟把图标换成透明占位下面这套流程我在 Windows 和 Linux 上都跑过Windows 上唯一多出来的一步是权限处理。4.1 先做备份别省这一步cd $(python -c import thonny,os;print(os.path.dirname(thonny.__file__))) mkdir -p _backup_res cp -r res _backup_res/ 2/dev/null || true或者更保险的做法直接把整个thonny包目录复制一份到旁边起名thonny.orig。这样即使你把某个.py改坏了也能整目录换回来。备份这件事在资源定制里尤其重要因为资源文件没有任何版本控制帮你兜底。4.2 生成一张同尺寸的透明 PNG不必依赖 Pillow纯标准库就能写出来机房环境里少装一个库就少一个坑import struct import zlib def write_transparent_png(path, width, height): raw b.join(b\x00 b\x00\x00\x00\x00 * width for _ in range(height)) def chunk(tag, data): head struct.pack(I, len(data)) tag data return head struct.pack(I, zlib.crc32(tag data) 0xFFFFFFFF) ihdr struct.pack(IIBBBBB, width, height, 8, 6, 0, 0, 0) png (b\x89PNG\r\n\x1a\n chunk(bIHDR, ihdr) chunk(bIDAT, zlib.compress(raw, 9)) chunk(bIEND, b)) with open(path, wb) as f: f.write(png) write_transparent_png(blank.png, 48, 32)宽高必须按你实际找到的那张原图来填。拿不准尺寸的话用前面那段遍历脚本配合PIL.Image.open(p).size看一眼或者干脆照着原图宽高填。尺寸不对虽然也能跑但布局可能出现偏移。4.3 覆盖并验证cp blank.png $(python -c import thonny,os;print(os.path.join(os.path.dirname(thonny.__file__),res)))/原文件名覆盖之后重新启动 Thonny第一件事是打开关于对话框看了一眼确认没有报错第二件事是正常敲几行代码、运行一次确认主界面没受影响第三件事是打开文件、切主题把常用交互过一遍。只验证图标本身是不够的因为资源目录里往往还躺着其他图标误伤的情况要靠完整走一遍流程才能发现。4.4 Windows 上的只读目录问题如果 Thonny 装在Program Files或者受管目录下覆盖会直接报权限错误。三个选择以管理员身份运行一次命令行做覆盖把 Thonny 重装到用户目录或者用pip install --user装一份到自己的环境里。我个人倾向于第二种一次装好后续所有改动都不用提权长期看省事得多。5. 改完之后怎么让它活下来升级、分发与批量部署改一次不难难的是三个月后这批机器还是你交付时的样子。5.1 升级会冲掉什么pip install --upgrade thonny或者安装包覆盖安装都会把整个thonny包目录重新写一遍你替换的资源文件、改过的.py全部回到原样。这一点必须提前知道否则会出现明明改过怎么又回来了的困惑而且因为改动无声无息地消失很容易被误判成改法无效。如果你改的是.py文件Python 会依据文件修改时间重新编译__pycache__里的缓存所以正常编辑后直接重启就能生效不需要手动删缓存。但如果 Thonny 是以某种打包形式安装的比如被压成 zip 或者冻结进可执行文件那么源码改动根本不会被读取这种情况下只能走重新打包的路线。5.2 写一个可重复执行的补丁脚本思路很简单脚本自己找到当前生效的 thonny 包目录把目标资源覆盖成透明图同时打印出改动的文件路径和大小。这样每次升级完跑一遍就行import os import shutil import thonny TARGET res # 目标资源目录 ICON 目标文件名.png BLANK os.path.join(os.path.dirname(__file__), blank.png) root os.path.dirname(thonny.__file__) for dirpath, dirnames, filenames in os.walk(root): if ICON in filenames: dst os.path.join(dirpath, ICON) shutil.copyfile(BLANK, dst) print(patched:, dst)把它和blank.png放在同一个目录双击即可运行。加上打印改动了哪些文件这一句是有意为之的——批量部署时你需要一份可以贴在交付记录里的输出。5.3 配置文件一起下发效果更统一界面定制只解决了外观使用体验的一致性还得靠配置。Thonny 的配置存在Thonny.ini里Windows 在%APPDATA%\Thonny\Linux 和 macOS 在~/.config/Thonny/。你在 Tools → Options 里调好的字体、缩进、自动保存、解释器路径等全在这个文件里。机房交付的常见做法是在一台机器上把所有设置调好把Thonny.ini拷出来批量分发到每台机器的对应目录覆盖前先退出 Thonny。这比让几十号人自己点一遍设置靠谱得多也避免了为什么他的缩进是 4 格我的是 8 格这类无意义的问答。注意Thonny.ini里可能记录了上次连接的串口、最近打开的文件路径等机器相关的内容。批量分发前建议把这几项清一下否则新机器上会残留别人的路径。6. 顺带聊聊 Thonny 的另一条主线ESP32-S3 与 ST7789 的配置之所以要在同一篇里说这块是因为我这次做界面定制起因就是实训室的嵌入式教学环境。Thonny 不只是个 Python 编辑器它在 MicroPython 教学里几乎是标配而一旦涉及几十台带屏幕的开发板环境统一和界面统一的诉求是一起出现的。6.1 解释器与串口这两个设置决定了大部分连不上Tools → Options → Interpreter 里选 MicroPython (ESP32)端口尽量手动指定不要依赖自动检测。自动检测在多设备同时插着的机器上经常认错口表现就是连上了但 REPL 没反应。Windows 上看设备管理器确认是哪个 COM 口Linux 上通常是/dev/ttyUSB0或/dev/ttyACM0用之前记得把自己加进对应的用户组并重新登录否则会出现权限被拒。如果板子上还没烧 MicroPython 固件可以用 Thonny 自带的安装器Interpreters 页面里点安装或更新固件芯片选 ESP32-S3选对端口按提示走完。手动方式也行esptool两个命令芯片参数写esp32s3写入偏移是0x0。烧录时如果一直提示连接失败按住板子上的 BOOT 键再上电进入下载模式通常就能过。REPL 里两个快捷键要记住CtrlC中断当前运行的程序CtrlD软重启。写屏幕驱动的时候这两个键会被反复用到尤其是代码跑飞导致 REPL 没响应的时候。6.2 点亮 ST7789 的接线与最小代码ST7789 是很常见的 SPI 小屏接线的关键是把 SPI 的时钟和数据线接对其余都是控制线。下面是一组可用的示例接法具体 GPIO 按你的板子调整屏幕引脚ESP32-S3 示例 GPIO说明VCC3V3供电别接 5VGNDGND共地必须接SCL / CLKGPIO12SPI 时钟SDA / MOSIGPIO11SPI 数据RESGPIO9复位DCGPIO8数据/命令选择CSGPIO10片选固定接低也能省一个引脚BLKGPIO7 或 3V3背光控制最小验证代码大致是这样from machine import Pin, SPI import st7789 spi SPI(2, baudrate40_000_000, polarity0, phase0, sckPin(12), mosiPin(11)) tft st7789.ST7789( spi, 240, 320, resetPin(9, Pin.OUT), dcPin(8, Pin.OUT), csPin(10, Pin.OUT), backlightPin(7, Pin.OUT), rotation0, ) tft.init() tft.fill(st7789.BLACK) tft.fill_rect(20, 20, 200, 100, st7789.RED)跑不通的时候排查顺序我一般是这样的先看背光亮不亮不亮是供电或背光引脚的问题再看屏幕是全白还是全黑全白多半是复位或初始化时序最后再怀疑 SPI 参数。花屏和颜色错乱九成是频率太高或者颜色顺序不对把 baudrate 从 40MHz 降到 20MHz 甚至 10MHz 试一次再把颜色顺序在 RGB 和 BGR 之间切一下基本能解决。这个降频排查法比反复检查代码有效得多。6.3 把驱动文件放进板子别每次往 REPL 里贴驱动代码动辄几百行直接贴在 REPL 里既占内存又难维护改一个参数就得重新贴一遍。正确做法是在 Thonny 里用另存为 MicroPython 设备把驱动文件存成板子上的模块文件之后import st7789就能直接用。板子文件系统空间有限上传前把驱动里的注释和用不到的示例代码删掉往往能省下可观的体积。上传完之后如果导入报错先确认文件名和模块名一致再确认板子文件系统里没有同名目录。这两个原因占了我遇到过的导入失败问题的绝大多数。6.4 界面定制和教学环境的真实关系讲到这里前面那条去掉图标的线索就和这块合上了。教学机房的机器是给学生用的界面里任何装饰性的、与写代码无关的元素都会变成课堂上的提问来源。把界面收干净把解释器路径、串口、驱动文件、示例代码全部预置好学生开机就能跑通第一个程序这才是交付的意义。界面定制看起来是个很小的事但它是整个环境统一工作的一部分做法和思路跟配置串口、预置驱动是完全一样的先定位再判断再写脚本固化下来。7. 排查清单改完图标之后最常见的几个问题最后把这一路踩过的坑整理成一份对照表遇到问题可以直接对着查。现象大概率原因处理方式重启后图标还在改的是另一份安装或者根本没重启用thonny.__file__确认实际加载路径点开关于直接报 TclError原文件被删了代码仍在加载换回同尺寸透明图不要删文件布局明显歪了替换图尺寸与原图不一致严格按原图宽高重新生成覆盖时报权限错误目录只读或需要管理员提权操作或改用用户目录安装升级后所有改动消失包目录被整体覆盖重跑补丁脚本或改用打包发行改了.py但行为没变安装形态不支持读源码确认是否为打包/冻结安装改完 Thonny 但 ESP32 连不上与图标改动无关是解释器和端口配置手动指定端口检查驱动和权限我个人在实际操作中的体会是这类改一个资源的需求真正花时间的从来不是改的动作而是确认改的是哪个文件、以及让改动在三个月后还能存活。所以哪怕只是给一台机器去掉一个图标我也会顺手把补丁脚本和备份一起留下。下次升级完跑一遍脚本三十秒状态就回到了你交付时的样子——这个习惯在机房环境里比任何技巧都值钱。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →