PyInstaller打包为exe后QSS设置的背景图片不显示如何修复
问题产生原因
核心是两点:
- 路径解析逻辑不兼容打包场景:Qt 样式表里写的相对路径
url(image.png),默认是从程序启动时的当前工作目录查找文件,不是从脚本所在目录、也不是从exe所在目录查找。直接运行.py脚本时,工作目录默认是脚本所在文件夹,和图片存放位置一致所以能正常加载;打包成exe后,启动时的工作目录完全可能是其他路径(比如快捷方式启动时的起始位置、其他程序调用时的调用方目录),自然找不到图片。 - 资源未被正确打包:PyInstaller默认只会打包py脚本依赖的代码文件,不会自动把你代码里引用的图片等静态资源打进去,就算路径写对了,包里根本没有image.png这个文件,也会加载失败。
可行修复方案
以下方案按推荐优先级从高到低排列:
方案1:使用qrc资源文件将图片编译进代码(最稳妥,无路径依赖)
这是PyQt官方推荐的静态资源管理方案,图片会被直接编译为Python字节码打包进exe,完全不需要处理外部路径问题,不会出现资源丢失、路径找不到的问题:- 在脚本和image.png同级目录新建
res.qrc文件,内容如下:
<RCC> <qresource prefix="/"> <file>image.png</file> </qresource> </RCC>- 用对应PyQt版本的rcc工具把qrc文件编译为py文件,PyQt5执行命令:
pyrcc5 res.qrc -o res_rc.py,PyQt6把命令里的pyrcc5替换为pyrcc6即可。 - 在你的业务代码顶部导入编译好的资源文件:
import res_rc - 修改样式表内的图片路径为qrc资源路径,不需要动态拼接路径:
stylesheet = """ QMainWindow { border-image: url(:/image.png) 0 0 0 0 stretch stretch; background-repeat: no-repeat; background-position: center; } """后续正常用PyInstaller打包即可,不需要额外加资源参数。
- 在脚本和image.png同级目录新建
方案2:动态适配运行路径,打包时附带外部图片
如果不想把图片编译进代码,就需要写兼容逻辑,不管是本地跑脚本还是打包后跑exe,都能精准定位到图片位置:- 先写一个跨场景的资源路径获取函数:
import sys import os def get_res_path(rel_path): if getattr(sys, 'frozen', False): # 打包后运行时,PyInstaller会把附带资源解压到临时_MEIPASS目录 base_dir = sys._MEIPASS else: # 本地运行脚本时,以当前脚本所在目录为基准 base_dir = os.path.dirname(os.path.abspath(__file__)) return os.path.join(base_dir, rel_path).replace('\\', '/')- 动态拼接样式表内的图片绝对路径:
bg_path = get_res_path("image.png") stylesheet = f""" QMainWindow {{ border-image: url({bg_path}) 0 0 0 0 stretch stretch; background-repeat: no-repeat; background-position: center; }} """- 打包时追加参数把图片带进包里,Windows系统下打包命令加
--add-data "image.png;.",macOS/Linux下把分号换成冒号即--add-data "image.png:."。
方案3:图片放在exe同级目录,支持后续替换
如果需要打包后还能自由替换背景图,不需要重新编译exe,只需要修改路径获取函数的基准目录为exe所在路径即可:def get_res_path(rel_path): if getattr(sys, 'frozen', False): # 打包后以exe所在目录为基准找资源 base_dir = os.path.dirname(os.path.abspath(sys.executable)) else: base_dir = os.path.dirname(os.path.abspath(__file__)) return os.path.join(base_dir, rel_path).replace('\\', '/')打包时不需要加
--add-data参数,打包完成后把image.png放到exe同级目录即可正常加载,后续替换图片直接覆盖同目录下的文件就行。
内容的提问来源于stack exchange,提问作者Ziv
相关产品推荐
相关产品推荐

