本文适用于 PySide6、PyQt5、PyQt6、PySide2 等各 PyQt 版本,不适用于 C++ Qt。
 
  Qt 资源系统简介 
Qt 资源系统(The Qt Resource System )是一种独立于平台的资源管理器,用于在应用程序的可执行文件中存储二进制文件。对 PyQt 而言,这意味着在 Python 代码中直接以二进制形式存储图标、QSS 、长文本翻译等资源文件。使用 Qt 资源管理系统可以有效防止资源文件丢失,对于需要打包发布的 PyQt 程序尤其实用。
在项目中使用 Qt 资源系统,大致分为三个步骤:编写 .qrc 文件、使用 rcc 编译资源、导入与使用。下文将一一详细讲解。
  qrc 文件 
  简介与示例 
Qt 资源集合文件(Qt Resource Collection File)一般以 .qrc 作为扩展名保存,故简称 .qrc 文件。其文件格式基于 XML ,用于将文件系统(硬盘)中的资源文件与 Qt 应用程序关联起来。.qrc 还可以实现为资源分组、设置别名等功能。
下面是一个简单的例子:
Resources 目录下包含图标、关于文档等资源文件。
1 2 3 4 5 6 7 8 $  tree Resources  Resources ├── Icons │   ├── Py2exe-GUI_icon_72px.png │   └── Python_128px.png ├── Texts │   └── About_zh.md └── resources.qrc
 
在此处新建一个 resources.qrc 文件,内容如下:
1 2 3 4 5 6 7 8 <!DOCTYPE RCC > <RCC >      <qresource >          <file > Icons/Py2exe-GUI_icon_72px.png</file >          <file > Icons/Python_icon.ico</file >          <file > Texts/About_zh.md</file >      </qresource > </RCC > 
 
注意文件的相对路径是以 .qrc 所在的目录 Resources\ 为根目录开始计算的。
 
这样便建立了硬盘上文件系统中原文件与 Qt 资源系统中资源路径 之间的联系。
  使用前缀进行分组 
在文件系统中,可以通过目录对不同类型的资源进行分组。在上面的例子中,图标文件都在 Icons/ 目录下,而长文本在 Texts/ 下。在 .qrc 中,也可以通过指定 <qresource> 标签的 prefix 属性来对资源进行分组:
1 2 3 4 5 6 7 8 9 10 <!DOCTYPE RCC > <RCC >      <qresource  prefix ="icons" >          <file > Icons/Py2exe-GUI_icon_72px.png</file >          <file > Icons/Python_icon.ico</file >      </qresource >      <qresource  prefix ="texts" >          <file > Texts/About_zh.md</file >      </qresource > </RCC > 
 
  为资源创建别名 
有些资源的文件名很长,每次使用时都输入完整文件名较为繁琐。可以通过在 <file> 标签中添加 alias 属性为其创建别名,方便未来在资源路径 中使用:
1 2 3 4 5 6 7 8 9 10 <!DOCTYPE RCC > <RCC >      <qresource  prefix ="icons" >          <file  alias ="Py2exe-GUI_icon" > Icons/Py2exe-GUI_icon_72px.png</file >          <file  alias ="Python_icon" > Icons/Python_icon.ico</file >      </qresource >      <qresource  prefix ="texts" >          <file  alias ="About_Text" > Texts/About_zh.md</file >      </qresource > </RCC > 
 
  使用 rcc 编译资源 
  rcc 简介 
Qt 提供了 Resource Compiler  命令行工具(简称 rcc),用于在构建过程中将资源嵌入 Qt 应用程序。对于 PyQt,也有对应版本的 rcc 工具,用于将 .qrc 中指定的资源文件数据编译至 Python 对象。
  rcc 的安装与基本使用 
当通过 pip 安装 PySide6 或其他 PyQt 时,会同时自动安装对应版本的 rcc 工具。这些工具的调用命令有所不同(详见下表),但使用方式与功能是一致的。激活已安装 PyQt 的 Python 虚拟环境,在命令行(注意不是 Python 交互式解释器)中输入对应的 rcc 命令即可。
平台 
rcc 命令名称 
 
 
PySide6 
pyside6-rcc 
 
PyQt5 
pyrcc5 
 
PySide2 
pyside2-rcc 
 
PyQt6 
不提供 
 
 
使用 PySide6 提供的 pyside6-rcc 工具编译出的 .py 文件,也可以放入 PyQt6 项目中使用,只需将文件开头的 from PySide6 import QtCore 替换为 from PyQt6 import QtCore 即可。
 
例如,对于 PySide6,在命令行调用命令
1 pyside6-rcc -o compiled_resources.py resources.qrc
 
即可将 resources.qrc 中列出的资源文件编译到输出文件 compiled_resources.py 中。
  rcc 命令行选项 
此处以 pyside6-rcc 6.4.1 为例,列出了完整的选项列表(翻译版):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 $  pyside6-rcc --help   Usage: /path/to/your/python3/site-packages/PySide6/Qt/libexec/rcc [options] inputs Qt Resource Compiler version 6.4.1 Options:   -h, --help                            显示关于命令行选项的帮助      --help-all                            显示包括Qt独有选项在内的所有帮助      -v, --version                         显示版本信息      -o, --output <file>                   将输出写入到 <file> 中,而不是 stdout 中   -t, --temp <file>                     为大资源文件使用临时文件 <file>      --name <name>                         用 <name> 创建一个外部初始化函数      --root <path>                         用根目录 <path> 作为资源访问路径的前缀      --compress-algo <algo>                使用 <algo> 算法压缩输入文件([zlib], none)      --compress <level>                    按 <level> 级别压缩输入文件      --no-compress                         禁用所有压缩,等同于 --compress-algo=none      --no-zstd                             禁止使用 zstd 压缩      --threshold <level>                   衡量是否值得进行压缩的阈值      --binary                              输出一个作为动态资源使用的二进制文件      -g, --generator <cpp|python|python2>  选择生成器      --pass <number>                       Pass number for big resources      --namespace                           关闭命名空间宏      --verbose                             启用 verbose 模式      --list                                只列出 .qrc 文件条目,不生成代码      --list-mapping                        只输出 .qrc 中定义的资源路径与文件系统路径的                                         映射,不生成代码                                            -d, --depfile <file>                  向 <file> 中写入一个包含 .qrc 依赖项的 depfile   --project                             输出一个包含当前目录下所有文件的资源文件      --format-version <number>             写入 RCC 格式的版本 Arguments:   inputs                                输入文件 (*.qrc)
 
  编译出的 Python 文件 
运行成功后,在 .qrc 中声明的所有资源文件都已经被编译到 compiled_resources.py 这个 Python 文件中,不妨打开查看其内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 from  PySide6 import  QtCore qt_resource_data = b"......"  qt_resource_name = b"......"  qt_resource_struct = b"......" def  qInitResources ():     QtCore.qRegisterResourceData(0x03 , qt_resource_struct, qt_resource_name, qt_resource_data)def  qCleanupResources ():     QtCore.qUnregisterResourceData(0x03 , qt_resource_struct, qt_resource_name, qt_resource_data) qInitResources()
 
最上方的注释标明了该文件由与 Qt6.4.1 版本匹配的资源编译器生成。并警告用户不要直接编辑该文件,因为所有修改都会被下一次编译操作覆盖掉。
接下来是三段长长的二进制编码字符串,其中正是资源文件:
qt_resource_data - 资源文件内容数据 
qt_resource_name - 资源文件名称 
qt_resource_struct - 资源结构 
 
还有两个函数 qInitResources() 与 qCleanupResources(),分别对应向 Qt 中注册资源与清理资源。
代码的最后一行调用了注册资源函数。
  在主程序中使用 
对于 PyQt 程序,从「直接加载使用资源文件」切换到「使用 Qt 资源系统读取资源」,还需要如下步骤:
在主程序中导入编译后的资源 
用「资源路径」替换「文件路径」 
由使用 Python 内置 open() 函数改为使用 Qt 中 QFile  类或 QDir  类提供的 open() 方法 
 
  导入编译后的资源 
在主程序中添加 import 导入语句,将刚才获得的 compiled_resources.py 导入:
1 import  compiled_resources  
 
因为 import 的过程会执行该模块中的所有代码,也就自动调用了 qInitResources() 函数,完成了资源的注册与加载。
PyCharm 等 IDE 可能将此行代码判断为 “未使用的 import 语句” 而提示一个弱警告。可以通过在该行末尾添加特殊的 # type: ignore 注释来显式告知静态检查器忽略此行,消除这种不必要的警告。
 
  资源路径 
对于直接使用资源原文件,会使用其在文件系统中的路径,例如
1 icon = QPixmap("Icons/Python_icon.ico" )
 
而在 Qt 资源系统中使用,则需要将文件路径替换为「资源路径」。资源路径由 .qrc 文件决定。
对于最一般的情况,直接在文件名前添加 :/ 即可得到其资源路径:
1 2 3 <qresource >      <file > Icons/Python_icon.ico</file > </qresource > 
 
1 icon = QPixmap(":/Icons/Python_icon.ico" )
 
对于有前缀进行分组的,则需要在文件名前添加 :/$prefix$/作为资源路径:
1 2 3 <qresource  prefix ="icons" >      <file > Icons/Python_icon.ico</file > </qresource > 
 
1 icon = QPixmap(":/icons/Icons/Python_icon.ico" )
 
对于指定了别名的,可以直接使用别名:
1 2 3 <qresource  prefix ="icons" >      <file  alias ="Py_ico" > Icons/Python_icon.ico</file > </qresource > 
 
1 icon = QPixmap(":/icons/Py_ico" )
 
资源路径也可以与 Qt 中的 QUrl  系统组合使用,在原有的资源路径前添加 qrc 即可:
1 QUrl("qrc:/myapp/main.qml" )
 
  读取资源文件 
需要使用 Qt 提供的 QFile  或 QDir  读取编译后的资源文件,而不再能使用 Python 提供的 open() 函数等。
例如,一段从 Markdown 文件中读取应用程序“关于”文本的代码,使用直接读取原资源文件的写法如下:
1 2 3 4 5 def  get_about_text ():     about_file = open ("Resources/About.md" , "r" , encoding="utf-8" )       about_text = about_file.read()     about_file.close()     return  about_text
 
而使用 Qt 资源系统后,需要修改为如下形式:
1 2 3 4 5 6 7 8 9 from  PySide6.QtCore import  QFile, QIODevicedef  get_about_text ():          about_file = QFile(":/texts/About_Text" )       about_file.open (QIODevice.ReadOnly | QIODevice.Text)       about_text = str (about_file.readAll(), encoding="utf-8" )       about_file.close()     return  about_text
 
TODO: 通过自行编写上下文管理器,实现 Python 风格的文件IO.
对于图片,可以在创建 QIcon 、QImage 、QPixmap  对象时将直接资源路径作为参数传入:
1 icon = QPixmap(":/icons/Python_icon.ico" )
 
  在 IDE 中配置 
  在 PyCharm 中配置使用 rcc 
可以将 rcc 工具添加至 PyCharm 中,避免每次使用都需要输入繁琐的命令行。(目前版本的 PyCharm 中已经原生内置了对 pyrcc4 和 pyside-rcc 的支持,但其他版本的 rcc 工具快捷使用仍需自行在「外部工具」中创建。)
打开 文件 -> 设置 -> 工具 -> 外部工具(File -> Settings -> Tools -> External Tools)
然后创建工具。配置可以参考下图,仍然以 pyside6-rcc 为例:
其中比较重要的是「工具设置」里面的三行配置:
1 2 3 程序:        $PyInterpreterDirectory$/pyside6-rcc 实参:        -o compiled_$FileNameWithoutExtension$.py $FileName$ 工作目录:     $FileDir$
 
其中凡是以一对 $ 包裹的字符,均为 PyCharm 提供的宏,分别代表「Python 解释器目录」、「不带扩展名的文件名」、「文件名」和「文件所在目录」。
完成配置后,在待编译的 .qrc 文件上打开右键菜单,找到「外部工具 - pyside6-rcc」,点击即可运行,非常方便。
  使用 VS Code 编辑 qrc 
安装 Qt for Python  插件后,VS Code 编辑器会对 .qrc 文件提供一定的语法高亮、亦可一键编译。
1 2 #  VS Code 插件安装命令:  ext install seanwu.vscode-qt-for-python
 
  使用 QtCreator 编辑 qrc 
直接在文本编辑器中以 XML 形式编写复杂的 .qrc 文件时,较为繁琐、易出错,可以考虑安装 Qt 官方的 QtCreator  IDE 来生成 .qrc 文件。
1 2 3 4 5 6 7 $  tree resource  resource ├── icon │   ├── ic_last_step.svg │   ├── ic_next_step.svg │   └── ic_start.svg └── res.qrc
 
首先启动 QtCreator,在 resource/ 目录中新建 res.qrc 文件:
然后以 icon 前缀创建一个分组:
接着用 Add Files 按钮把图标文件添加进来,并保存:
此时得到了 res.qrc:
1 2 3 4 5 6 7 <RCC >      <qresource  prefix ="/icon" >          <file > icon/ic_last_step.svg</file >          <file > icon/ic_next_step.svg</file >          <file > icon/ic_start.svg</file >      </qresource > </RCC > 
 
为了缩短引用路径,还可以为每个图标文件设置别名(alias):
现在得到这样的 res.qrc:
1 2 3 4 5 6 7 <RCC >      <qresource  prefix ="/icon" >          <file  alias ="ic_last_step" > icon/ic_last_step.svg</file >          <file  alias ="ic_next_step" > icon/ic_next_step.svg</file >          <file  alias ="ic_start" > icon/ic_start.svg</file >      </qresource > </RCC > 
 
  进阶话题 
  国际化多语言 
有时应用程序需要在不同的语言环境下使用不同的文件,可以通过设置 lang 属性来轻松实现。下面是一个例子:
1 2 3 4 5 6 <qresource >      <file > cut.jpg</file > </qresource > <qresource  lang ="fr" >      <file  alias ="cut.jpg" > cut_fr.jpg</file > </qresource > 
 
当系统语言为其他语言时,Qt 程序将会使用文件 cut.jpg;而当系统语言为法语时,会自动替换为 cut_fr.jpg。
  压缩 
rcc 会尝试压缩内容以优化硬盘空间使用。默认情况下,它将进行启发式检查以确认是否值得压缩。如果不能充分压缩,则将直接存储非压缩的内容。可以使用 -threshold 选项 控制此判断的阈值。例如,默认情况下阈值为 70,表示只有在压缩后的文件比原文件小 70%(不超过原文件大小的 30%)时才有必要压缩。
1 rcc -threshold 25 myresources.qrc
 
在某些情况下也可以关闭压缩功能。一种常见情况是,某些资源已经是压缩后的格式(例如 .png 文件),再次压缩几乎不会进一步减小文件体积,但会占用 CPU 成本。另一种情况是,硬盘空间非常充裕,期望应用程序在运行时可以将内容存储在干净的内存页中。在命令行 中添加 -no-compress 命令以关闭压缩。
1 rcc -no-compress myresources.qrc
 
还可以控制 rcc 使用的压缩算法与压缩级别,例如:
1 rcc -compress 2 -compress-algo zlib myresources.qrc
 
表示使用 zlib 压缩算法,压缩等级为 2。
除了在命令行调用 rcc 时指定选项,还可以在 .qrc 文件中控制阈值、压缩算法与压缩等级:
1 2 3 <qresource >      <file  compress ="1"  compress-algo ="zstd" > data.txt</file > </qresource > 
 
rcc 具体支持的压缩算法类型与压缩等级,参见官方文档 。
  参考资料 
Qt6 官方文档:The Qt Resource System  
Qt6 官方文档:Resource Compiler (rcc)  
Qt for Python 官方教程:Using .qrc Files (pyside6-rcc)  
pyside6(1):Qt 资源系统和qrc文件使用  
Stack Overflow: How can resources be provided in PyQt6 (which has no pyrcc)?