警告

本节包含从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-670/6.7.0/Src/qtbase/resource-system/application.qrc" not found>

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.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文件可以设置一个前缀,用于添加到在<file>元素中给出的每个本地文件名,以获得文件在资源系统中的名称。

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

注意

/qt/qt-project.org前缀是为Qt中记录的使用情况保留的。例如,在:/qt/etc/qt.conf中查找qt.conf文件或qrc:/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>

然后 resulting 文件仍然可以从应用程序访问,但内容为空。

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

注意

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

语言选择器#

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

<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

您还可以将 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文件的基准名称。例如

def __init__(self, BaseClass():

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

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

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