警告

本节包含从C++自动翻译到Python的代码片段,可能包含错误。

Qt资源系统

一种平台无关的机制,用于在应用程序中分发资源文件。

Qt资源系统是一种平台无关的机制,用于在应用程序中分发资源文件。如果你的应用程序总是需要一组特定的文件(如图标、翻译文件、图像),并且你不想使用特定于系统的方式来打包和定位这些资源,那么可以使用它。

最常见的情况是,资源文件被嵌入到您的应用程序可执行文件中,或者嵌入到由应用程序可执行文件加载的库和插件中。另外,资源文件也可以存储在外部资源文件中。

资源系统基于Qt的rcc资源编译器、构建系统和Qt运行时API之间的紧密合作。

注意

目前,Qt资源系统没有利用任何系统特定的功能来处理资源,例如Windows、macOS和iOS上的功能。这可能会在未来的Qt版本中发生变化。

Qt资源编译器 (rcc)

资源编译器(rcc)命令行工具读取资源文件并生成C++或Python源文件,或.rcc文件。

文件和相关的元数据列表以Qt资源集合文件的形式传递给rcc

默认情况下,rcc 会生成 C++ 源代码,然后将其编译为可执行文件或库的一部分。-g python 选项则生成 Python 源代码。-binary 选项生成一个二进制存档,按照惯例保存在 .rcc 文件中,并可以在运行时加载。

注意

虽然可以从命令行运行rcc,但这通常最好留给构建系统。另请参阅下面关于qmakeCMake的部分。

Qt 资源收集文件 (.qrc)

一个 .qrc 文件是一个 XML 文档,它列举了要作为运行时资源包含的本地文件。它作为 rcc 的输入。

这是一个示例 .qrc 文件:

<Code snippet "/data/qt5-full-681/6.8.1/Src/qtbase/resource-system/application.qrc" not found>

XML中的每个元素标识应用程序源树中的一个文件。路径是相对于包含.qrc文件的目录解析的。

路径在默认情况下也用于在运行时识别文件的内容。也就是说,文件 titlebarLeft.png 将在资源系统中作为 :/res/titlebarLeft.pngqrc:/res/titlebarLeft.png 可用。要覆盖此默认运行时名称,请参阅 PrefixesAliases

Qt Creator, Qt Design Studio, Qt Widgets Designer, 和 Qt Visual Studio Tools 允许您通过方便的用户界面创建、检查和编辑 .qrc 文件。除了 Qt Widgets Designer 外,它们还提供了使用 Qt 资源系统的项目向导。

构建系统集成

资源文件的处理通常在应用程序构建时使用rcc完成。一些构建工具对此有专门的支持,包括CMakeqmake

CMake

如果启用了CMAKE_AUTORCC,你可以直接将.qrc文件作为源文件添加到你的可执行文件或库中。引用的资源文件随后将被嵌入到二进制文件中:

set(CMAKE_AUTORCC ON)

qt_add_executable(my_app
    application.qrc
    main.cpp
)

有关 AUTORCC 的更多详细信息,请参阅 CMake 的 AUTORCC 文档

AUTORCC 的替代方案是使用 Qt6Core 的 CMake 函数 qt_add_resources,它提供了对资源创建的更多控制。例如,它允许您直接在项目文件中指定资源的内容,而无需先编写 .qrc 文件:

qt_add_resources(my_app "app_images"
    PREFIX "/"
    FILES
        images/copy.png
        images/cut.png
        images/new.png
        images/open.png
        images/paste.png
        images/save.png
)

最后,qt_add_qml_module 允许你将 Qt Quick 资源嵌入到应用程序的资源系统中。该函数定义在 Qml 组件的 Qt6 CMake 包中。

qmake

qmake 支持使用 RESOURCES 变量处理资源。如果你将一个 .qrc 文件路径添加到该变量中,列出的资源文件将被嵌入到生成的库或可执行文件中:

RESOURCES = application.qrc

这将创建几个.png文件的资源,这些文件可以像这样访问:":/res/titlebarLeft.png"

如果您想要嵌入到资源中的文件的目录布局与应用程序的预期不匹配,您可以指定resources.basebase是一个路径前缀,表示文件别名的根点。在上面的例子中,如果resources.base设置为"res",那么titlebarLeft.png可以作为":/titlebarLeft.png"进行访问。

运行时API

处理迭代和读取文件的Qt API内置支持Qt资源系统。你可以传递资源路径而不是本地文件路径给QFileQDir,同样也可以传递给QIcon、QImage和QPixmap的构造函数:

cutAct = QAction(QIcon(":/images/cut.png"), tr("Cut"), self)

: 前缀明确表示“/images/cut.png”应从 Qt 资源系统中加载。

你也可以通过QUrl引用Qt资源系统。在这种情况下使用qrc方案:

engine = QQmlApplicationEngine()
engine.load(QUrl("qrc:/myapp/main.qml"))

高级主题

前缀

一个.qrc文件可以为每个本地文件名设置一个前缀,该前缀在元素中给出,以获取文件在资源系统中应被识别的名称。

前缀允许您结构化资源,避免通过不同库或插件中的不同.qrc文件添加的资源文件之间的冲突。

注意

/qt/qt-project.org 前缀是为 Qt 中记录的使用案例保留的。例如,qt.conf 文件会在 :/qt/etc/qt.confqrc:/qt/etc/qt.conf 中查找。

别名

有时在运行时以不同的路径提供资源文件是很方便的。.qrc 文件通过设置 alias 属性来实现这一点:

<file alias="cut-img.png">images/cut.png</file>

该文件来自应用程序,只能作为 :/cut-img.pngqrc:/cut-img.png 访问。

丢弃文件内容

有时您想向资源文件系统添加一个文件节点,但实际上并不想添加文件内容。.qrc 文件通过将 empty 属性设置为 true 来允许这种情况。

<file empty="true">Button.qml</file>

生成的文件仍然可以从应用程序中访问,但其内容为空。

这对于从应用程序二进制文件中剥离QML源代码非常有用。

注意

如果你从二进制文件中省略了QML源代码,QML引擎必须依赖于由qmlcachegen或qmlsc创建的编译单元。这些编译单元与它们构建时使用的特定版本的Qt绑定。如果你更改了应用程序使用的Qt版本,它们将无法再加载。

语言选择器

一些资源需要根据用户的语言环境进行更改,例如翻译文件或图标。资源集合文件通过lang属性支持这一点,该属性附加到qresource标签上,指定一个合适的语言环境字符串。例如:

<qresource>
    <file>cut.jpg</file>
</qresource>
<qresource lang="fr">
    <file alias="cut.jpg">cut_fr.jpg</file>
</qresource>

如果用户的区域设置为法语(即system() .language() 为法语),:/cut.jpgqrc:/cut.jpg 将引用 cut_fr.jpg 图像。对于其他区域设置,使用 cut.jpg

请参阅QLocale文档,了解用于区域设置字符串的格式描述。

请参阅QFileSelector以获取选择特定区域资源的其他机制。

嵌入大文件

默认情况下,rcc 将资源文件以 C++ 数组的形式嵌入到可执行文件中。这对于大型资源尤其可能造成问题。

如果编译器花费太长时间,甚至因为内存溢出而失败,您可以选择一种特殊模式,在这种模式下,资源作为两步过程的一部分被嵌入。C++编译器仅在目标可执行文件或库中为资源保留足够的空间。资源文件内容和元数据的实际嵌入是在编译和链接阶段之后,通过另一个rcc调用来完成的。

对于CMake,你需要使用qt_add_big_resources函数。

外部资源文件

将资源文件嵌入二进制文件的替代方法是将它们存储在一个单独的.rcc文件中。rcc允许使用-binary选项来实现这一点。这样的.rcc文件必须在运行时使用QResource加载。

例如,在.qrc文件中指定的一组资源数据可以通过以下方式编译:

rcc -binary myresource.qrc -o myresource.rcc

在应用程序中,此资源将使用如下代码进行注册:

QResource.registerResource("/path/to/myresource.rcc")

如果您使用CMake,您可以使用qt_add_binary_resources函数来安排上面的rcc调用:

qt_add_binary_resources(resources application.qrc DESTINATION application.rcc)
add_dependencies(my_app resources)

Qt for Python 应用程序中的资源

资源集合文件通过使用资源编译器 rcc 转换为 Python 模块:

rcc -g python mainwindow.qrc > mainwindow_rc.py

然后可以在应用程序中导入该模块:

import mainwindow_rc.py

压缩

rcc 尝试压缩内容以优化最终二进制文件中的磁盘空间使用。默认情况下,它会执行启发式检查以确定压缩是否值得,如果无法充分压缩,则会以未压缩的形式存储内容。要控制阈值,您可以使用 -threshold 选项,该选项告诉 rcc 必须达到原始文件大小的百分比才能以压缩形式存储文件。

rcc -threshold 25 myresources.qrc

默认值为“70”,表示压缩文件必须比原始文件小70%(不超过原始文件大小的30%)。

如果需要,可以关闭压缩。如果您的资源已经包含压缩格式,例如.png文件,并且您不想在构建时承担CPU成本来确认它无法压缩,这可能很有用。另一个原因是,如果磁盘使用不是问题,并且应用程序希望在运行时保持内容为干净的内存页面。您可以通过提供-no-compress命令行参数来实现这一点。

rcc -no-compress myresources.qrc

rcc 还允许您控制压缩级别和压缩算法,例如:

rcc -compress 2 -compress-algo zlib myresources.qrc

也可以在.qrc file 标签中使用 compressthreshold 作为属性。要选择算法,请设置 compression-algorithm 属性。

<qresource>
    <file compress="1" compression-algorithm="zstd">data.txt</file>
</qresource>

上述操作将选择压缩级别为1的zstd算法。

rcc 支持以下压缩算法和压缩级别:

  • best: 使用下面算法中最好的一个,在其最高压缩级别下,以在编译期间使用大量CPU时间为代价,实现最大的压缩。这个值在XML文件中很有用,用于指示文件应该被最大程度地压缩,而不管rcc支持哪些算法。

  • zstd: 使用Zstandard库来压缩内容。有效的压缩级别范围从1到19,1表示最低压缩(最少的CPU时间),19表示最高压缩(最多的CPU时间)。默认级别为14。特殊值0告诉zstd库选择一个实现定义的默认值。

  • zlib: 使用 zlib 库来压缩内容。有效的压缩级别范围从1到9,1表示应用最少的压缩(最少的CPU时间),9表示应用最多的压缩(最多的CPU时间)。特殊值0表示“无压缩”,不应使用。默认值是实现定义的,但通常是级别6。

  • none: 无压缩。这与 -no-compress 选项相同。

对Zstandard和zlib的支持是可选的。如果在编译时未检测到给定的库,尝试为该库传递-compress-algo将会导致错误。默认的压缩算法是zstd(如果启用),否则是zlib

显式加载和卸载嵌入式资源

嵌入在C++可执行文件或库代码中的资源会在内部全局变量的构造函数中自动注册到Qt资源系统中。由于全局变量在main()运行之前初始化,因此当程序开始运行时,资源已经可用。

在将资源嵌入静态库时,C++链接器可能会移除注册资源的静态变量。因此,如果您将资源嵌入静态库中,您需要通过调用Q_INIT_RESOURCE()并传入.qrc文件的基本名称来显式注册您的资源。例如:

def __init__(self, BaseClass():

    Q_INIT_RESOURCE(resources)
    file = QFile(":/myfile.dat")
    ...

你也可以显式地从应用程序中移除已注册的资源,例如在卸载插件时。为此,请使用Q_CLEANUP_RESOURCE()

注意:由于由rcc生成的资源初始化器是在全局命名空间中声明的,因此您对Q_INIT_RESOURCE()Q_CLEANUP_RESOURCE()的调用需要在任何命名空间之外进行。