QtResources SimplifiedChinese

From Qt Wiki
Revision as of 11:08, 25 February 2015 by Maintenance script (talk | contribs)
Jump to navigation Jump to search

简体中文 English

[toc align_right="yes" depth="1"]

概述

资源是将包括图像、声音等任意二进制数据作为应用程序二进制的一部分进行嵌入的标准方式。详情参见 "文档":http://doc.qt.nokia.com/snapshot/resources.html。

Qt的资源与Windows下的 RES 文件 或 Mac OS X 系统下的资源分支(resource forks)没有任何联系。

它是如何工作的

资源文件(也就是 .qrc 文件)是用来指定哪些文件应该被打包进最终的二进制文件的XML文件。资源编译器 rcc 解析该XML并生成C/ C+代码。生成的代码中有一个包含 .qrc 中列出的所有文件的原始字节的C struct。就像文件可以可以按层次结构安排一样,这些C 结构体聚集到另一个C 结构体中形成一个树状结构。这些C 结构体本身细节不是太有趣,所以不在这里讨论它。通过为 rcc 指定 -compressed 选项,结构体中的数据可以使用 zlib 进行压缩(默认情况下,压缩是未启用的)。

要想被Qt了解,这些 C 结构体需要被注册。诀窍是,在每一个 rcc 生成的 C+ 文件的结尾,rcc放置了一个将该C结构体注册到Qt资源系统的函数 qRegisterResourceData() 的调用。通过使用 构造函数模式(onstructor function pattern) qRegisterResourceData() 在 main() 之前被调用。_构造函数模式_ 是 全局静态变量通过调用一个函数来初始化它自身的用法。

#ifndef Q_CONSTRUCTOR_FUNCTION
# define Q_CONSTRUCTOR_FUNCTION0(AFUNC)  static const int AFUNC ## ''init_variable'' = AFUNC ();
# define Q_CONSTRUCTOR_FUNCTION(AFUNC) Q_CONSTRUCTOR_FUNCTION0(AFUNC)
#endif

rcc 生成的 C++ 文件的尾部包含类似下面的东西:

int qInitResources_images()
{
 qRegisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data);
 return 1;
}

Q_CONSTRUCTOR_FUNCTION(qInitResources_images)

由于静态变量在 main() 被调用之前完成初始化,所有的资源在程序真正启动之前自动完成注册。

Q_INIT_RESOURCE

上述构造函数技巧只有在生成的C+文件被直接编译并链接到主应用程序时才工作。如果资源用在静态库中而后该库被链接进主应用程序中,构造函数将永远不会被调用。这是由C/C+链接的本质——库中未被最终应用程序使用或调用的函数和变量将从库中被移除(优化掉)。如果资源位于共享库中,构造函数也不被调用。尽管如此,大多数平台上根据需求加载动态库,而该构造函数只在共享库被导入时被调用。其结果是,除非插件本身被加载主应用程序使用的的位于插件中的任何资源都会找不到 —— 如果在共享库中的资源只用于该共享库这不是一个问题。请注意,在主应用程序的一个共享对象内部访问资源并不会触发共享对象的加载,因为没有符号被QRC系统导出以用来触发共享对象的加载。

对上述问题的一个解决方案是使用生成的变量(上面提到的 AFUNC##_init_variable_)或者调用上面生成的qInitResource_images()。宏Q_INIT_RESOURCE 存在的意义就在于此而 当你的静态或共享库中有资源时它是必须的

#define Q_INIT_RESOURCE_EXTERN(name)  extern int qInitResources_ ## name();

对每一个qrc文件,上面的宏通常都放在main函数的开始。

访问资源

QFile、QDir、QPixmap 等都可访问 qrc文件。在Qt中,所有的文件都是通过 "QAbstractFileEngine":http://doc.trolltech.com/4.6/qabstractfileengine.html 被访问的。当文件名有 ":" 前缀时,QResource 在启动时注册一个提供了有效文件系统引擎(通过QAbstractFileEngine::create)的 QAbstractFileSystemEngine 的派生类对象。

资源命名空间化(Namespacing resources)

当在插件中使用资源时,资源路径必须命名空间化。使用插件名称作为资源的命名空间是一个很好的技术。例如,_:/plugin_name/resourcename_ 。如果现有的资源文件的路径已被不同的数据注册,它会被忽略从而第一个被保留。