跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Python

PyQt6 项目开发:虚拟环境修复与 PyInstaller 打包常见问题解决

解决了 PyQt6 程序运行时闪退及打包后找不到模块的问题。主要步骤包括:检查并重建被破坏的虚拟环境(.venv),修复 QTextCursor 兼容性问题;使用 PyInstaller 打包时添加 --collect-all 和 --add-data 参数确保资源文件正确包含;处理图标显示问题,区分 exe 文件图标与窗口图标。通过清理构建目录、指定正确的解释器路径及资源路径,最终实现程序正常运行。

kaikai发布于 2026/3/30更新于 2026/7/2555 浏览
PyQt6 项目开发:虚拟环境修复与 PyInstaller 打包常见问题解决

在这里插入图片描述

运行程序后,窗口如图;但是闪退。报错如下。C:\Users\CQJY\Desktop\PythonProject.venv\Scripts\python.exe C:\Users\CQJY\Desktop\PythonProject\main.py 进程已结束,退出代码为 -1073740791 (0xC0000409)

在这里插入图片描述

现在这个新报错:

程序'python.exe'无法运行:指定的可执行文件不是此操作系统平台的有效应用程序。

几乎可以肯定是 .venv\Scripts\python.exe 被破坏/替换(或和基准 Python 不一致)。之前它还能跑、能弹'Qt ok',说明不是系统位数问题,而是后来 venv 里的 python.exe 损坏了(最常见是误用 Set-Content、杀毒拦截/隔离、或复制覆盖)。

按下面做,最快恢复:

A. 对比一下:venv 的 python.exe 是否异常

# 在项目根 cd C:\Users\CQJY\Desktop\PythonProject # 看大小与版本信息
(Get-Item .\.venv\Scripts\python.exe).Length 
(Get-Item .\.venv\Scripts\python.exe).VersionInfo | fl ProductVersion,FileVersion 
# 与基准 Python 对比(应接近相同)
(Get-Item "C:\Users\CQJY\AppData\Local\Programs\Python\Python313\python.exe").Length 

如果 venv 里的体积很小/为 0 或与基准差异巨大,就是被破坏了。

B. 直接重建 .venv(最稳妥)

# 关掉 PyCharm,避免占用 .venv
cd C:\Users\CQJY\Desktop\PythonProject
Remove-Item -Recurse -Force .\.venv
# 用你已安装的 3.13/64 重建
py -3.13 -m venv .venv
# 快速自检
.\.venv\Scripts\python.exe -V
.\.venv\Scripts\python.exe -c "import struct,platform;print('arch=',struct.calcsize('P')*8,'os=',platform.platform())"
# 重新装依赖
.\.venv\Scripts\python.exe -m pip install -U pip
.\.venv\Scripts\python.exe -m pip install PyQt6 pyserial # 串口建议用 pyserial,更稳

⚠️ 小心别再对可执行文件用 Set-Content、Out-File 等命令;这些会把二进制覆盖成文本,立刻变成'不是有效应用程序'。

C. 再做一次最小自检(确保 PyQt 正常)

$probe = @'
from PyQt6.QtWidgets import QApplication, QWidget
import sys
app = QApplication(sys.argv)
w = QWidget(); w.setWindowTitle("probe"); w.show()
print("Qt ok")
sys.exit(app.exec())
'@
Set-Content -Path .\_qt_probe.py -Value $probe -Encoding UTF8
.\.venv\Scripts\python.exe .\_qt_probe.py 

D. 跑你的项目前,记得修掉上一个 PyQt6 兼容问题

你之前的异常在:

ui\widgets.py:177 -> self.moveCursor(self.textCursor().End) 

改为:

from PyQt6.QtGui import QTextCursor
self.moveCursor(QTextCursor.MoveOperation.End)
# 或:
cur = self.textCursor()
cur.movePosition(QTextCursor.MoveOperation.End)
self.setTextCursor(cur)
self.ensureCursorVisible()

然后再跑:

.\.venv\Scripts\python.exe .\main.py 

在这里插入图片描述

E. 仍有问题?两个应急方案

  1. 重装一次基准 Python 3.13(64-bit)
    基准被杀软拦截/损坏时,重装可一并修复,之后再重建 .venv。

用基准 Python 直跑(验证是否仅 venv 问题)

"C:\Users\CQJY\AppData\Local\Programs\Python\Python313\python.exe" .\main.py 

如果缺包,就在 venv 中 pip freeze > requirements.txt,然后对基准环境 pip install -r requirements.txt --user(临时验证用)。

一句话总结
  • 这次是 .venv\Scripts\python.exe 被破坏 导致的'不是有效应用程序'。
  • 删除 .venv → 重建 → 重新装依赖 就能恢复;随后把上次的 QTextCursor 写法改掉,程序应能正常运行。
  • 以后只对 .py 文件 用 Set-Content;不要对 .exe / .dll 之类二进制用这些命令。

打包成功后双击 exe 文件会有这个弹窗报错。

在这里插入图片描述

报错窗口里写得很直白:No module named 'PyQt6'。
意思是打包产物里没把 PyQt6 包进去(或运行时没能找到它),所以 exe 一启动、执行到 import PyQt6 就挂了。

最常见原因与修法👇(按顺序做,基本一次好):

0)快速确认问题点

在 dist 目录里看一眼(你现在是 onedir 形态,PyInstaller 6.x 会把内容放到 _internal 子目录里):

  • 应该能看到:
    dist\Diginv_BAT32G139\_internal\lib\PyQt6\__init__.py 等一堆文件/Qt 插件目录。
  • 如果 没有 PyQt6 这个目录,就印证了:打包时没收进去。

1)确认你用的是项目 venv里的 Python,且里面有 PyQt6

你的路径里有空格与括号,后续命令都要加引号并用调用运算符 &。

cd "C:\Users\CQJY\Desktop\PythonProject_20251106_14_30 V1.1.3(阶段性成功)"
# 1) 这个 python 应该是你项目的 .venv
& ".\.venv\Scripts\python.exe" -c "import sys; print(sys.executable)"
# 2) 这里必须能 import PyQt6(否则先安装)
& ".\.venv\Scripts\python.exe" -c "import PyQt6, sys; print('OK:', PyQt6.__file__)"
# 若报错,再装:
& ".\.venv\Scripts\python.exe" -m pip install -U PyQt6 

如果上一步 OK,说明你的构建环境有 PyQt6,继续第 2 步。

2)清理后用更稳的打包命令重建(收全 PyQt6)

先删老的构建输出,再用'全收集'参数:

Remove-Item -Recurse -Force .\build,.\dist,.\Diginv*.spec -ErrorAction SilentlyContinue
& ".\.venv\Scripts\python.exe" -m pip install -U "pyinstaller>=6.7"
# onedir(便于检查)
& ".\.venv\Scripts\pyinstaller.exe" `
 --noconfirm --clean --windowed `
 --name Diginv_BAT32G139 `
 --collect-all PyQt6 `
 --collect-submodules PyQt6 `
 --collect-data PyQt6 `
 --collect-binaries PyQt6 `
 --hidden-import PyQt6 `
 --hidden-import PyQt6.QtWidgets `
 --hidden-import PyQt6.QtCore `
 --hidden-import PyQt6.QtGui `
 --hidden-import PyQt6.QtSerialPort `
 --add-data".\ui\assets;ui\assets" `
 --icon ".\ui\assets\app.ico" `
 .\main.py 
PS C:\Users\xsshu\Desktop\Python\random_pro> & ".\.venv\Scripts\pyinstaller.exe" `
 >> --noconfirm --clean --windowed `
 >> --name RandomGame_V1.0.2 `
 >> --collect-all PyQt6 `
 >> --collect-submodules PyQt6 `
 >> --collect-data PyQt6 `
 >> --collect-binaries PyQt6 `
 >> --hidden-import PyQt6 `
 >> --hidden-import PyQt6.QtWidgets `
 >> --hidden-import PyQt6.QtCore `
 >> --hidden-import PyQt6.QtGui `
 >> --hidden-import PyQt6.QtSerialPort `
 >> --add-data".\ui\asset;ui\asset" `
 >> --icon ".\ui\asset\main_windows_ico_32.png" `
 >> .\main.py 

解释 --collect-all PyQt6 通常已足够,但个别环境里加上 --collect-submodules/--collect-data/--collect-binaries 和几个 --hidden-import 更保险。这些参数不改你源码,只是指导 PyInstaller 把 PyQt6 的包体与 Qt 插件全部打进来。构建完成后,dist\Diginv_BAT32G139\_internal\lib\PyQt6\... 就应该有了。

在这里插入图片描述

(这里基本上就打包成功了。但会遇到个图标显示的问题,参考后面的解释。)

确认 onedir 能运行后,再出 onefile:

& ".\.venv\Scripts\pyinstaller.exe" `
 --noconfirm --clean --windowed --onefile `
 --name Diginv_BAT32G139 `
 --collect-all PyQt6 `
 --collect-submodules PyQt6 `
 --collect-data PyQt6 `
 --collect-binaries PyQt6 `
 --hidden-import PyQt6 `
 --hidden-import PyQt6.QtWidgets `
 --hidden-import PyQt6.QtCore `
 --hidden-import PyQt6.QtGui `
 --hidden-import PyQt6.QtSerialPort `
 --add-data".\ui\assets;ui\assets" `
 --icon ".\ui\assets\app.ico" `
 .\main.py 

3)若仍出同样错,用 spec 文件'锁死'收集规则

在项目根新建 Diginv.spec(这不是改源码),内容:

# Diginv.spec
from PyInstaller.utils.hooks import collect_submodules, collect_data_files, collect_dynamic_libs

hiddenimports = collect_submodules('PyQt6')
datas = collect_data_files('PyQt6')
binaries = collect_dynamic_libs('PyQt6')
# 带上你的资源
datas += [('ui/assets','ui/assets')]

block_cipher = None
a = Analysis(['main.py'], pathex=[], binaries=binaries, datas=datas, hiddenimports=hiddenimports, hookspath=[], runtime_hooks=[], excludes=[], noarchive=False)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
 pyz, a.scripts, a.binaries, a.zipfiles, a.datas,
 name='Diginv_BAT32G139', console=False,# windowed
 icon='ui/assets/app.ico')
coll = COLLECT(exe, a.binaries, a.zipfiles, a.datas, name='Diginv_BAT32G139')

打包:

Remove-Item -Recurse -Force .\build,.\dist -ErrorAction SilentlyContinue
& ".\.venv\Scripts\pyinstaller.exe" .\Diginv.spec 

4)其他容易忽略的小坑

  • 用错解释器:务必用 & ".\.venv\Scripts\pyinstaller.exe",别用全局 pyinstaller。
  • PyInstaller 版本:建议 ≥ 6.7(对 Python 3.13 与新打包结构更稳)。
  • 路径/权限:尽量避免将 dist 放在受限目录下,或被杀软清空 _internal。
  • 杀软误杀:onefile 形态解压到临时目录时容易被拦;先用 onedir 验证,再考虑发布 onefile 或让对方加白名单。
复盘你这次的现象
  • dist 里只有一个 exe + _internal 文件夹、但运行提示找不到 PyQt6 → 基本就是 _internal\lib 里没 PyQt6 包(或被杀软删了)。
  • 通过上面'全收集 + 清理重打'的命令,通常一次解决。
  • 打好 onedir 后,先确认 _internal\lib\PyQt6 是否存在,再双击运行。

需要的话,你把 构建日志里关于 PyQt6 的几行(WARNING: Hidden import not found 之类)贴出来,我可以据此最小化参数(把多余的 --hidden-import 去掉),保证以后打包命令更干净。


在执行 2)清理后用更稳的打包命令重建(收全 PyQt6)的时候报错:

在这里插入图片描述

报错的意思是:你传给 --icon 的那个 app.ico不是一个符合要求的 Windows ICO(很可能是 PNG 改后缀、或只包含 PNG-压缩的条目、或文件损坏)。在 Windows 上 PyInstaller 只接受 .ico 或 .exe 的图标资源。如果安装了 Pillow,它可以把 PNG 等自动转成合规 ICO;否则就抛出你看到的错误。

给你三个'立刻可用'的修法,任选其一就能过去(都不改你项目源码)。

方案 A:安装 Pillow,然后直接用 PNG 当图标

cd "C:\Users\CQJY\Desktop\PythonProject_20251106_14_30 V1.1.3(阶段性成功)"
& ".\.venv\Scripts\python.exe" -m pip install -U pillow
# 重新打包时把 --icon 指向 PNG(PyInstaller 会借助 Pillow 自动转成 .ico)

确保 .\\ui\\assets\\app.png 存在,最好是正方形 256×256 带透明背景。

在这里插入图片描述

如图所示,为什么不打包单独运行 main.py 的时候主页左上角的图标正常显示,但是打包 exe 文件后,可执行文件的 logo 是有了,但是进入主页的左上角图标没有了。

在这里插入图片描述

原因很简单:
Explorer 里看到的 exe 图标 是 --icon 给 exe 设置的'文件图标';
窗口左上角的图标 是你的代码里 setWindowIcon(QIcon("...")) 去加载的运行时图片文件。
打包后,这个图片没有出现在 exe 运行目录的预期位置(或被放进 _internal/临时目录里,程序用相对路径找不到),于是窗口就显示成默认的小白框。

你截图里的 onedir 产物里,exe 旁边只有 _internal,没有 ui\assets\...,说明 --add-data 并没把资源放到你代码期望的相对路径。

立刻可用的两种修法(不改任何源码)

方案 A:把资源按'原相对路径'放到 exe 旁(推荐)

清理后重打,确保把 ui\assets 整个目录复制到 exe 旁,并且目标子目录名保持一致:

cd "C:\Users\CQJY\Desktop\PythonProject_20251106_14_30 V1.1.3(阶段性成功)"
Remove-Item -Recurse -Force .\build,.\dist,.\Diginv*.spec -ErrorAction SilentlyContinue
# 用项目 venv 的 PyInstaller
& ".\.venv\Scripts\python.exe" -m pip install -U pyinstaller
# onedir(便于检查)
& ".\.venv\Scripts\pyinstaller.exe" `
 --noconfirm --clean --windowed `
 --name Diginv_BAT32G139 `
 --collect-all PyQt6 `
 --add-data"ui\assets;ui\assets" ` # ← 关键:把整个 ui\assets 带到 dist\...\ui\assets
 --icon "ui\assets\app.ico" `
 .\main.py 

打完后检查:

dist\Diginv_BAT32G139\
Diginv_BAT32G139.exe
ui\assets\app.ico ← 必须存在
ui\assets\...其他图片...
_internal\...

现在双击运行,窗口左上角图标应恢复正常。

注意:在 PowerShell 里,--add-data 的分隔符是 ;(我们已用对了);不要写成 ".\ui\assets;ui\assets" 也没问题,但更稳的是去掉 . 直接用相对路径 "ui\assets;ui\assets";若你只想带单个文件,也可以多写几条:
--add-data "ui\assets\app.png;ui\assets" --add-data "ui\assets\app.ico;ui\assets"

方案 B:直接把资源手动拷到 exe 旁

不想重打也行:把你项目里的 ui\assets 整个文件夹手动复制到

dist\Diginv_BAT32G139\ui\assets\ 

保证文件名/相对路径与源码一致(比如源码里写的是 ui/assets/app.png 就要有这条路径)。再次运行,窗口图标立即正常。

为什么单独 python main.py 正常、打包后不正常?

  • 你在源码环境下的工作目录正好就是项目根,ui/assets/... 能被找到;
  • 打包后(尤其 PyInstaller 6.x 的 onedir 新布局),很多文件被放进 _internal;如果你没把资源复制到 exe 旁的相同相对路径,QIcon("ui/assets/...") 找不到文件,Qt 不会抛异常,只是静默失败显示默认图标。

想发 onefile 也保留原相对路径(仍然不改源码)?

onefile 会把资源解压到临时目录,与你的相对路径不一致;在不改源码的前提下,建议:

  • 对外发 onedir 版本(最稳);
  • 或发 onefile 的同时 附带一个 ui\assets 文件夹(但这就不是纯单文件了)。

真要 onefile 且纯单文件,就需要在代码里用 sys._MEIPASS 定位解包目录——这就属于'改源码',与你当前约束冲突。

小结
  • 你现在的问题是资源未在预期路径。
  • 解决:用 --add-data "ui\assets;ui\assets" 让打包产物中出现 dist\...\ui\assets\...;或手工把该目录拷到 exe 旁。
  • exe 的'文件图标'与窗口图标是两回事:--icon 只设置前者;后者取决于运行时加载到的图片文件。

效果演示

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

目录

  1. A. 对比一下:venv 的 python.exe 是否异常
  2. 在项目根 cd C:\Users\CQJY\Desktop\PythonProject # 看大小与版本信息
  3. 与基准 Python 对比(应接近相同)
  4. B. 直接重建 .venv(最稳妥)
  5. 关掉 PyCharm,避免占用 .venv
  6. 用你已安装的 3.13/64 重建
  7. 快速自检
  8. 重新装依赖
  9. C. 再做一次最小自检(确保 PyQt 正常)
  10. D. 跑你的项目前,记得修掉上一个 PyQt6 兼容问题
  11. 或:
  12. E. 仍有问题?两个应急方案
  13. 一句话总结
  14. 0)快速确认问题点
  15. 1)确认你用的是项目 venv里的 Python,且里面有 PyQt6
  16. 1) 这个 python 应该是你项目的 .venv
  17. 2) 这里必须能 import PyQt6(否则先安装)
  18. 若报错,再装:
  19. 2)清理后用更稳的打包命令重建(收全 PyQt6)
  20. onedir(便于检查)
  21. 3)若仍出同样错,用 spec 文件“锁死”收集规则
  22. Diginv.spec
  23. 带上你的资源
  24. 4)其他容易忽略的小坑
  25. 复盘你这次的现象
  26. 方案 A:安装 Pillow,然后直接用 PNG 当图标
  27. 重新打包时把 --icon 指向 PNG(PyInstaller 会借助 Pillow 自动转成 .ico)
  28. 立刻可用的两种修法(不改任何源码)
  29. 方案 A:把资源按“原相对路径”放到 exe 旁(推荐)
  30. 用项目 venv 的 PyInstaller
  31. onedir(便于检查)
  32. 方案 B:直接把资源手动拷到 exe 旁
  33. 为什么单独 python main.py 正常、打包后不正常?
  34. 想发 onefile 也保留原相对路径(仍然不改源码)?
  35. 小结
  36. 效果演示
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 基于 Skill 与 MCP 的 Spring AI 应用落地实践
  • VisionTransformer(ViT)在时间序列行为识别中的应用
  • GitHub Copilot Pro 学生免费权益获取与 VS Code 配置指南
  • 华为昇腾 910B 使用 LLaMA-Factory 微调 Qwen3.5-32B 模型 LoRA 指南
  • 宇树科技机器人核心技术
  • 网络安全 CTF 竞赛入门指南:学习路线与实战建议
  • DeepSeek-R1-Distill-Llama-8B 本地部署与推理性能优化
  • Claude Skills 开源仓库精选与安装配置实战指南
  • 91n 边缘计算设备部署轻量 TensorFlow 模型全流程
  • 前端实现浏览器桌面通知功能
  • OpenClaw 完全指南:部署 7×24 小时开源 AI 助手
  • MindAR 多目标追踪实战:构建交互式乐队 AR 应用
  • Java 调用 CPLEX 优化器:安装配置与示例
  • Vue3 H5 端纯前端人脸识别与活体检测方案
  • Python 文本乱码原因及解决方案
  • 基于 Java 和高德开放平台 WebAPI 的 POI 搜索集成实践
  • 从零开始使用 IsaacLab 训练自己的机器人行走
  • C/C++ 位运算符详解
  • 使用 GitHub Copilot 和 Figma MCP 还原设计稿生成前端代码
  • Python 布尔类型基础

相关免费在线工具

  • curl 转代码

    解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online