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文件的示例

<RCC>
    <qresource prefix="/">
        <file>images/copy.png</file>
        <file>images/cut.png</file>
        <file>images/new.png</file>
        <file>images/open.png</file>
        <file>images/paste.png</file>
        <file>images/save.png</file>
    </qresource>
</RCC>

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

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

Qt CreatorQt Design StudioQt DesignerQt Visual Studio Tools允许您通过便捷的用户界面创建、检查和编辑.qrc文件。除了Qt 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资源嵌入到应用程序的资源系统中。该函数定义在Qt6 CMake包的Qml组件中。

qmake

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

RESOURCES = application.qrc

这创建了包含几个.png文件的资源,可通过以下方式访问:":/res/titlebarLeft.png"

如果要将文件嵌入资源中的目录布局与应用程序的预期不匹配,您可以指定resources.base。其中,base是表示文件别名根点的路径前缀。在上例中,如果resources.base设置为"res",则titlebarLeft.png可通过以下方式访问:":/titlebarLeft.png"

运行时API

Qt API处理迭代和读取文件的接口具有内置的对Qt资源系统的支持。您可以将资源路径传递给QFileQDir,也可以传递给例如QIconQImageQPixmap构造函数

    cutAct = new QAction(QIcon(":/images/cut.png"), tr("Cu&t"), this);

使用:前缀明确指出"/images/cut.png"应从Qt资源系统中加载。

您还可以通过QUrl引用Qt资源系统。在这种情况下,请使用qrc方案

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

高级主题

前缀

一个.qrc文件可以设置一个前缀,用于添加到<file>元素中给出的每个本地文件名,以便通过资源系统中应使用的名称来获取该文件

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

注意:前缀qt.conf文件在代码中的查找通常是在:/qt/etc/qt.confqrc:/qt/etc/qt.conf中。

别名

有时在运行时让资源文件可用在不同路径下是很方便的。通过设置 alias 属性,.qrc 文件允许这样做。

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

如果文件来自应用程序,那么它只能以 :/cut-img.pngqrc:/cut-img.png 的形式访问。

忽略文件内容

有时你想将文件节点添加到资源文件系统中,但实际上不希望添加文件内容。通过将 empty 属性设置为 true.qrc 文件允许这样做。

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

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

这对于从应用程序二进制文件中删除 QML 源代码很有用。

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

语言选择器

一些资源需要根据用户的地区进行更改,例如翻译文件或图标。资源集合文件 通过给 qresource 标签添加 lang 属性来支持此功能,指定一个合适的地区字符串。例如

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

如果用户的地区是法语(例如,QLocale::system() 的语言是法语),:/cut.jpgqrc:/cut.jpg 将成为指向 cut_fr.jpg 图像的引用。对于其他地区,使用 cut.jpg

有关地区字符串使用的格式说明,请参阅 QLocale 文档。

有关选择特定地区资源的功能,请参阅 QFileSelector

嵌入大型文件

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

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

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

外部资源文件

将资源文件嵌入到二进制文件的替代方法是将其存储在一个单独的 .rcc 文件中。使用 -binary 选项,rcc 允许这样做。这样一个 .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

也可以将thresholdcompresscompress-algo作为.qrc file标签的属性使用。

<qresource>
    <file compress="1" compress-algo="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 文件的基名来显式注册您的资源。例如

MyClass::MyClass() : BaseClass()
{
    Q_INIT_RESOURCE(resources);

    QFile file(":/myfile.dat");
    ...
}

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

注意:由于由rcc生成的资源初始化器在全局命名空间中声明,您调用 Q_INIT_RESOURCE() 和 Q_CLEANUP_RESOURCE() 需要在任何命名空间外部完成。

© 2024 The Qt Company Ltd. 本文档贡献的版权为各自所有者的版权。本提供的文档是依据自由软件基金会发布的 GNU自由文档许可证版本1.3 条款许可的。Qt及其相应标志是芬兰和其他国家/地区的 The Qt Company Ltd. 的商标。所有其他商标均为其各自所有者的财产。