Python Tkinter 程序打包单文件 exe 完整教程(Base64 内嵌图标,解决窗口 / 任务栏 /exe 三处图标自定义,无资源缺失报错) 前言
前言
使用tkinter+pyinstaller打包GUI程序时,会遇到3个典型痛点:
- 打包后exe文件夹图标、软件窗口左上角、任务栏图标全是默认软盘;
- 直接读取本地ico文件打包,运行提示
bitmap "app.ico" not defined崩溃; - 单文件
--onefile模式丢失DLL、解压失败闪退。
本文采用Base64内嵌图标 + spec配置文件打包方案,一次性解决全部图标问题,分发仅需单个exe,无需附带任何图片资源。
前置依赖
- 开发环境:Python3.11 + 虚拟环境venv
- 项目依赖:
ttkbootstrap、openpyxl、pyttsx3、pywin32 - 打包工具:
pyinstaller
安装全部依赖命令:
pip install pyinstaller ttkbootstrap openpyxl pyttsx3 pywin32步骤1:准备标准ICO图标文件
- 图标规范:必须是
.ico格式,内置多尺寸(256/128/64/32/16px),纯色简约图案,避免渐变透明花屏; - 在线转换工具:convertio.co/png-to-ico,上传图片导出全套尺寸ico;
- 项目目录新建
img文件夹,放入图标logo.ico,目录结构:
your-app/ ├─ img/ │ └─ logo.ico ├─ core/ ├─ ui/ ├─ main.py └─ icoToBase64.py步骤2:ICO转Base64脚本,将图标编码存入Python文件
新建icoToBase64.py,作用:把ico二进制转为base64字符串,写入img/logo.py,实现图标内置代码,打包无需外置图片。
importbase64# 读取ico二进制文件withopen("./img/logo.ico","rb")asf:icon_raw=f.read()# 转换base64编码icon_b64=base64.b64encode(icon_raw)# 写入img/logo.py,存储图标编码withopen("./img/logo.py","w",encoding="utf-8")asout_file:out_file.write(f"imgBase64 ={icon_b64}\n")运行脚本:
python icoToBase64.py执行后img目录生成logo.py,图标永久内置代码,不依赖外部文件。
步骤3:改造主程序main.py,动态生成临时图标(窗口+任务栏图标)
3.1 完整main.py核心代码
importbase64importosimportatexitimportttkbootstrapastb# 导入base64编码图标fromimg.logoimportimgBase64fromcore.data_storeimportload_all_cardsfromui.main_windowimportcreate_main_window# 全局临时图标路径temp_icon_path=""defcreate_temp_icon()->str:"""从base64解码生成系统临时ico文件"""globaltemp_icon_path# 生成临时ico,可替换为tempfile存入系统缓存,不残留文件temp_icon_path="temp.ico"withopen(temp_icon_path,"wb+")asf:f.write(base64.b64decode(imgBase64))returntemp_icon_pathdefclean_temp_icon():"""程序退出自动删除临时ico,兜底捕获异常"""globaltemp_icon_pathifos.path.exists(temp_icon_path):try:os.remove(temp_icon_path)exceptException:passdefmain():# 1. 生成临时图标create_temp_icon()# 注册程序退出钩子,无论正常关闭/闪退都清理临时文件atexit.register(clean_temp_icon)# 2. 创建主窗口root=tb.Window(themename="flatly")root.title("我的应用")root.geometry("710x550")root.resizable(True,True)# 3. 设置窗口左上角、任务栏图标root.wm_iconbitmap(temp_icon_path)# 绑定窗口关闭事件defclose_window():clean_temp_icon()root.destroy()root.protocol("WM_DELETE_WINDOW",close_window)# 业务逻辑初始化all_word_list=load_all_cards()create_main_window(root,all_word_list)root.mainloop()if__name__=="__main__":main()优化升级(可选,彻底消除exe目录残留temp.ico)
使用系统临时文件夹存放ico,不会在exe同级生成文件,替换create_temp_icon函数:
importtempfiledefcreate_temp_icon()->str:globaltemp_icon_path tmp=tempfile.NamedTemporaryFile(suffix=".ico",delete=False)tmp.write(base64.b64decode(imgBase64))tmp.close()temp_icon_path=tmp.namereturntemp_icon_path步骤4:生成&修改PyInstaller打包配置spec文件
4.1 生成spec模板
终端执行命令,自动创建main.spec配置文件:
pyi-makespec--onefile--windowed main.py参数说明:
--onefile:打包为单exe文件;--windowed:无黑色控制台窗口。
4.2 修改spec,自定义exe文件图标(文件夹显示图标)
打开main.spec,找到底部EXE配置块,修改icon参数,指定ico路径:
exe=EXE(pyz,a.scripts,a.binaries,a.zipfiles,a.datas,[],name='我的应用',# 打包后exe文件名debug=False,bootloader_ignore_signals=False,strip=False,upx=True,upx_exclude=[],runtime_tmpdir=None,console=False,# 关闭黑窗口,和--windowed等价disable_windowed_traceback=False,argv_emulation=False,target_arch=None,codesign_identity=None,entitlements_file=None,icon='./img/logo.ico'# 打包嵌入exe文件图标)注意:
icon路径是打包时读取,本地项目必须存在img/logo.ico,仅用于修改exe二进制资源,不参与程序运行。
步骤5:执行打包命令生成exe
5.1 清理旧缓存(必做,解决图标缓存不刷新)
手动删除项目内3个文件/文件夹:build、dist、main.spec(重新生成全新spec)
5.2 执行spec打包
pyinstaller main.spec5.3 打包完成产物
项目根目录生成dist文件夹,内部我的应用.exe为最终成品单文件程序。
最终效果说明
- exe文件夹图标:spec配置
icon参数控制,分发到任意电脑都显示自定义图标; - 软件窗口左上角图标:Base64动态生成临时ico渲染;
- Windows任务栏图标:跟随tkinter窗口图标自动同步;
- 分发仅需单个exe,无需附带图片、json资源,全部内置代码/打包二进制。
拓展:文件夹打包模式(兼容性最强,推荐复杂项目)
若项目依赖pyttsx3语音、openpyxl表格库,单文件极易闪退,去掉--onefile打包:
- 生成spec命令:
pyi-makespec --windowed main.py; - 打包后dist为完整文件夹,整体分发,无DLL缺失、解压失败问题。
