跳至主要內容

Qt

LincZero大约 7 分钟

Qt

目录

.qrc 资源文件

这个机制有点特别,以前没碰到过。好像没相对路径这种东西?需要先添加资源文件,可能和编译机制有关吧

qrc文件

简概

在QtCreator中双击不能打开,需要右击选择打开方式

  • Open in Editor,Qt的资源编辑器
  • Open with
    • 资源编辑器,同Open in Editor
    • 文本编辑器,以代码形式打开
    • 二进制编辑器,如名
    • System Editor,用电脑自带的编辑器

其中文本编辑器打开,代码如下

<RCC>
    <qresource prefix="/form">			// 前缀为/from
        <file>mainwindow.ui</file>		// 该前缀下的资源
    </qresource>
</RCC>

优点

底层原理深入解析

参考:

观察

test.qrc 在工程构建后回生成以下两个文件

  • qrc_test.cpp
  • qrc_test.obj

注意这两个只是编译过程产生的文件,删除不影响程序正常运行。资源已经被嵌入仅exe文件里了

原理

  • qrc文件

    qrc文件本身类似于一个XML格式的文本,用文本编辑器打开则可以看到其XML格式的代码。其记录了所包含的每一个文件的路径

  • 编译过程

    关键在于,使用rcc/pyrcc5/pyside2-rcc对该文件进行编译时,

    程序遍历qrc文件里面的每一个文件路径,将该文件的二进制内容写入到相应的输出文件里。

  • 举例(pyside2-rcc编译)

    使用的all_day.csv文件是一个纯文本文件,其文件大小为56.4KB;包含该文件路径信息的data.qrc文件大小为85字节;通过pyside2-rcc.exe编译生成的data_rc.py文件大小为70.7KB。(qrc只包含资源路径而不包含文件?)

    此外,当我编译完成了data_rc.py之后,即使我删除all_day.csv文件,程序照样能够正常运行并读取all_day.csv里面的数据。除了pyside2-rcc.exe将all_day.csv的所有信息统统写进了编译生成的data_rc.py这种解释外,我实在想不到为什么一个py文件能够达到70.7KB。

  • qrc文件特性

    有了前面的结论,也就很好解释qrc文件的一些相关特性了,例如:

    1. 目标程序里所有内嵌的资源文件都是只读的,在程序运行时不能修改资源里的文件,只能读取使用。
    2. 当你修改了qrc资源文件包含的任意文件之后,你必须重复添加-编译的操作才能使更改生效。
    3. 除了Qt之外的程序想要直接从编译后的文件里面获取信息几乎是不可能的,必须要借助Qt内部接口读取资源文件信息。

rcc 编译工具

RCC 代表 反向 C 编译器(Reverse C Compiler)(不确定)

Qt 自带的开发工具集里有专门的 rcc 工具,用于将 *.qrc 里面描述的图片、文档等编译成对应的源代码文件 qrc_*.cpp 或者独立的二进制资源文件 *.rcc。下面介绍 rcc 工具的两种用途:

  • (1) 生成独立的二进制资源文件 *.rcc
  • (2) 应用程序内嵌资源

生成独立的二进制资源文件 *.rcc

  • 二进制资源文件 *.rcc

    • 对于太大的图片、音频、视频等文件,不适合集成到目标程序内部,可以放到操作系统文件路径,或者单独编译成外挂资源 *.rcc
    • myresource.qrc 包含了很多图片和视频,没法编译成目标程序内嵌资源时,可以打包成 rcc文件,操作如下
  • 打包成rcc

    • 打开 Qt 命令行,进入 myresource.qrc 所在的文件夹,执行命令:

      rcc -binary myresource.qrc -o myresource.rcc

    • rcc 会把 myresource.qrc 里面描述的所有图片、视频等文件,都压缩打包,生成一个二进制的 myresource.rcc 文件,这个 myresource.rcc 包含了所有的资源,这样程序发布时就不需要带一堆乱七八糟的碎文件了,一个 myresource.rcc 搞定

  • 使用rcc资源

    • 那么代码中如何使用 myresource.rcc 呢?

    • 需要在 main 函数开始的位置注册这个独立的二进制资源文件

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

    • 然后也是使用之前类似的虚拟文件路径,比如 ":/images/copy.png" 、":/images/cat.gif" 。

应用程序 ”内嵌资源“

  • 内嵌资源

    • 比起外挂的二进制资源文件*.rcc,应用程序里面更常见的是内嵌资源,接下来介绍内嵌使用方式
  • 内嵌方法

    • 如果希望一个资源描述文件 application.qrc 在程序编译时内嵌到目标程序里,需要在 *.pro 文件里加一句话:

      RESOURCES += application.qrc

      qmake 会自动根据这句话,为 application.qrc 添加编译脚本,其编译过程如下

  • 编译流程

    • 图解

      ![rcc](03.%20.qrc 资源文件.assets/ch05-06-01.png)

    • 文字说明

      • (1) rcc 工具会解析 application.qrc 内的 XML 文本,找到需要添加的各种文件,
      • (2) 默认情况下,rcc 工具会对这些文件做 ZIP 压缩,然后将压缩后的 ZIP 数据的每个字节转换成比如 0x6f的数值形式,
      • (3) 所有文件压缩后的数据对应一个 C++ 静态数组 qt_resource_data[] ,并添加注册、取消注册、初始化、清除等函数和资源描述结构体,
      • (4) 最终形成一个 qrc_application.cpp 文件。然后用编译器编译 qrc_application.cpp文件,得到 qrc_applicaotion.o ,链接到目标程序内部,就可以用 ":/images/copy.png" 等形式访问程序内嵌资源了。
    • qrc_*.cpp 细节

      • // ...
        static const unsigned char qt_resource_data[] = {
          // D:/Project/Dev/Platform/Multi/Qt/Test/UseOfficalQtPlugin/UseOfficalQtPlugin/mainwindow.ui
          0x0,0x0,0x3,0xe4,
          0x3c,
          0x3f,0x78,0x6d,0x6c,0x20,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x3d,0x22,0x31,0x2e,
          0x30,0x22,0x20,0x65,0x6e,0x63,0x6f,0x64,0x69,0x6e,0x67,0x3d,0x22,0x55,0x54,0x46,
          0x2d,0x38,0x22,0x3f,0x3e,0xd,0xa,0x3c,0x75,0x69,0x20,0x76,0x65,0x72,0x73,0x69,
          0x6f,0x6e,0x3d,0x22,0x34,0x2e,0x30,0x22,0x3e,0xd,0xa,0x20,0x3c,0x63,0x6c,0x61,
          // ...这里大概有60多行的0x00的数值形式
          0x73,0x6f,0x75,0x72,0x63,0x65,0x73,0x2f,0x3e,0xd,0xa,0x20,0x3c,0x63,0x6f,0x6e,
          0x6e,0x65,0x63,0x74,0x69,0x6f,0x6e,0x73,0x2f,0x3e,0xd,0xa,0x3c,0x2f,0x75,0x69,
          0x3e,0xd,0xa,
        };
        // ...
        
  • 其他补充

    • qmake 为内嵌资源添加的 rcc 编译命令,类似下面这样:

      rcc -name application application.qrc -o qrc_application.cpp

    • 应用程序的内嵌资源通常不需要手动初始化,但也有例外情况,比如在使用某些链接库中的资源文件时,如果出现使用了正确的文件路径 ":/images/copy.png" 却找不到资源里图片文件的情况,那么需要在使用该资源的类声明里或者在 main 函数里打头的位置加入一句手动初始化:

      Q_INIT_RESOURCE(resources);,resources 是指 resources.qrc 的简短名字形式,不需要扩展名

使用

添加qrc工程资源

步骤:

  • (1) 把文件夹或文件置于项目文件夹中
  • (2) 项目管理器中右键 > 点击添加新文件 > Qt > Qt Resource File > 起名配置 会生成一个资源类别的资源名.qrc文件
  • (3) 右击选择Open in Editor的方式打开qrc资源文件并进入编辑界面
  • (4) 添加 > 添加前缀(Add Prefix) > 如不添加则填/ (默认为/new/prefix1
  • (5) 添加 > 添加文件(Add File) > 选择项目文件 需要先添加并选择前缀才能添加文件。可以选多个文件,而不能选文件夹)
  • (6) 编译后即可 成功的话项目文件夹中的qrc文件会多出可折叠的资源 且.pro文件会自动附加一行配置:RESOURCES += \XXX.qrc

使用qrc工程资源

步骤:

  • 通用:: + 前缀名 + 文件名
  • 举例:QAction,ui->actionNew->setIcon(":/source/favicon.ico");
  • 举例:QLabel,ui->qlabel->setPixmap(QPixmap(":/Image/butterfly.png"));
  • 举例:QLabel+动图
    • (1) 头文件,#include <QMovie>
    • (2) 创建QMovie对象,QMovie * movie = new QMovie(":/Image/mario.gif");
    • (3) 添加到QLabel中,ui->qlabel->setMovie(movie);
    • (4) 播放动图,movie->start();

ui界面中使用qrc工程资源,步骤:

  • 直接选择就行

使用qrc注意项

  1. 为了管理方便,需要编译进qrc资源文件的那些文件最好放在.qrc的所在文件夹或者其子文件夹内
  2. 前缀(prefix)注意项
    • 在不加前缀的前提下 在程序中调用同级资源文件可以使用(":file_name")file = QFile(":/all_day.csv"); 调用子目录资源文件可以用(":path/to/file")file = QFile(":/resources/all_day.csv")
    • 在加前缀的情况下 在程序中调用同级资源文件可以使用(":/prefix/file_name")file = QFile(":/data/all_day.csv"); 调用子目录资源文件可以用(":/prefix/path/to/file")file = QFile(":/data/resources/all_day.csv")
  3. 对于文件大小超过4M的文件,不建议直接编译,而是使用选项-binary,具体文档看这里open in new window。另外,在Qt的python绑定中不支持-binary