简述

Qt 的资源系统用于存储应用程序的可执行二进制文件,它采用平台无关的机制。当你的程序总需要这样的一系列文件(图标、翻译文件等)并且不想冒丢失某些文件的风险时,这就显得十分有用。
资源系统基于 qmake、rcc(Qt 资源编译器) 和 QFile 之间的紧密合作。

资源集合文件(.qrc)

与程序相关的资源在被指定在一个 .qrc 文件中,其基于 XML 的文件格式列出了磁盘上的文件,可以为它们指定一个应用程序访问资源时必须使用的资源名称。

下面是一个 .qrc 文件的示例:

  1. <!DOCTYPE RCC><RCC version="1.0">
  2. <qresource>
  3. <file>images/copy.png</file>
  4. <file>images/cut.png</file>
  5. <file>images/new.png</file>
  6. <file>images/open.png</file>
  7. <file>images/paste.png</file>
  8. <file>images/save.png</file>
  9. </qresource>
  10. </RCC>

.qrc 文件中列出的资源文件是程序代码树中的一部分。指定的路径相对于 .qrc 文件所在目录。注意:列出的资源文件必须位于 .qrc 文件所在目录或其子目录。

资源数据可以编译成二进制,进而在程序代码中立即访问;或者创建一个二进制资源,在晚些时候用资源系统来注册程序代码。

默认情况下,程序可以使用与代码树中相同的名字访问资源,需要带有 “:/” 前缀,或者有qrc scheme的URL。
例如: :/images/cut.png 或者URL qrc:///images/cut.png 都可以访问在程序代码树中位置为 images/cut.png 的 cut.png 文件。用文件标签的别名属性可以改变访问名称:

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

之后,在程序中就可以使用 :/cut-img.png 访问此文件了。还可以使用 qresource 标签的前缀属性为 .qrc 文件中列出的所有文件指定路径前缀:

  1. <qresource prefix="/myresources">
  2. <file alias="cut-img.png">images/cut.png</file>
  3. </qresource>

这种情况下,就可以使用 :/myresources/cut-img.png 访问该文件了。

有些资源可能需要随着用户本地的配置而改变,例如:翻译文件、图标,可以通过为 qresource 标签添加一个 lang 属性,并指定一个适当的本地字符串来完成。例如:

  1. <qresource>
  2. <file>cut.jpg</file>
  3. </qresource>
  4. <qresource lang="fr">
  5. <file alias="cut.jpg">cut_fr.jpg</file>
  6. </qresource>

如果用户的语言是法语(即:QLocale::system().name() 返回“fr_FR”),:/cut.jpg 就变成了对 cut_fr.jpg 文件的引用。如果是其它语言,仍然使用 cut.jpg 。

使用语言字符串的格式的说明可以参考 QLocale 文档。

外部二进制资源

要创建外部二进制资源,必须通过传递 -binary 给 rcc 来创建资源数据(通常使用 .rcc 扩展名),一旦二进制资源被创建,就可以使用 QResource API 注册该资源。

例如, .qrc 文件中指定的一系列资源数据可以用下面的方式编译:

  1. rcc -binary myresource.qrc -o myresource.rcc

在程序里,需要用以下代码注册该资源:

  1. QResource::registerResource("/path/to/myresource.rcc");

内编译资源

要把一个资源编译到二进制文件中, 必须在 .pro 中明确指定.qrc 文件,以便于 qmake 可以正确处理。例如:

  1. RESOURCES = application.qrc

qmake 会产生 make 规则来生成一个链接到程序中的名为 qrc_application.cpp 的文件。这个文件以静态的 C++ 压缩二进制数组包含了所有图片和其它资源的数据。当 qrc_application.cpp 本身或者是其引用的资源文件发生改变后,该文件都会被自动重新生成。如果你不使用 .pro 文件,那么可以手工调用 rcc 或者为 build 系统添加 build 规则。
20160722142714326.png
目前,Qt 总是把资源数据存储在可执行文件中,甚至是在 Windows、Mac OS X 和 iOS 这些原生支持资源机制的操作系统中。在将来的 Qt release 版本中可能会改变。

压缩

默认情况下,资源是被压缩的(ZIP 格式),也可以关闭压缩。如果你的资源已经包含了一个压缩格式(例如: .png 文件),这可能会比较有用。可以通过命令行传递 -no-compress 来指定:

  1. rcc -no-compress myresources.qrc

rcc 也在压缩上给你提供了一些控制,当压缩文件时,可以指定压缩级别和阈值水平时,例如:

  1. rcc -compress 2 -threshold 3 myresources.qrc

在程序中使用资源

在程序中,资源路径在大多数情况可以代替一般的文件系统路径。特别是,可以用资源路径取代文件名传递给 QIcon、 QImage ,或者 QPixmap 的构造函数:

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

可以参考 Application 示例,了解更多关于应用程序使用 Qt 资源系统来存储图标的内容。

在内存中,资源由一个资源对象树来表示。此树在程序启动时被自动生成,并被 QFile 用来解析路径到资源。你可以使用带有 “:/” 前缀的 QDir 从根目录开始遍历这棵树。

Qt 资源系统支持搜索路径列表。如果你用 : 代替 :/ 作为前缀,则会使用搜索路径列表来搜索资源。程序启动时搜索路径列表为空,可以用 QDir::addSearchPath() 为其添加路径。

在库中使用资源

如果有资源位于一个库中,需要用不带有后缀的 .qrc 文件名为参数调用 Q_INIT_RESOURCE() 来强制初始化资源系统。例如:

  1. MyClass::MyClass() : BaseClass()
  2. {
  3. Q_INIT_RESOURCE(resources);
  4. QFile file(":/myfile.dat");
  5. ...
  6. }

在静态链接的情况下,这确保了资源被链接到最终应用程序的二进制文件中。应该把初始化代码接近库中资源被使用的地方,这样以来,如果库的客户端用库的特性,它们只会链接进资源。

注意:由于 rcc 初始化资源生成在全局命名空间中声明,你也需要在任何命名空间之外的地方调用 Q_INIT_RESOURCE()。

如果库内部包含未使用的资源,但是暴漏给库的客户端,初始化需要发生在应用程序代码中,例如:

  1. int main(int argc, char *argv[])
  2. {
  3. QApplication app(argc, argv);
  4. Q_INIT_RESOURCE(graphlib);
  5. QFile file(":/graph.png");
  6. ...
  7. return app.exec();
  8. }

和之前一样,这确保在静态链接的情况下,资源被链接到最终应用程序的二进制文件中,也触发加载动态链,例如:插件。

同样的,你必须明确地卸载一个显式设置的资源(因为一个插件被卸载或资源不再有效),你可以强制删除资源通过调用 Q_CLEANUP_RESOURCE() 与上面相同的基本名称。

注意:**当资源被构建为应用程序的一部分时,没有必要使用 Q_INIT_RESOURCE() 和Q_CLEANUP_RESOURCE()。