Qt中使用图片资源的方法有很多种,以前我一直分不清各种之间的区别和Qt相应的处理机制,后来遇到一些实际的问题,然后再加上查阅源码和资料,总算弄明白一些事情,但是本文仅仅是个人理解,如有错误之处请告诉我,大家一起进步。

图片是一种资源,而在Qt中,对于资源的使用是有其独特的方式的!

①:一般来说:资源在内存中是用资源对象树来表示的,该树在程序启动时创建。

②:而对于资源而言:我们都是需要先将其加入到这棵树中才能加载到内存中并被程序使用!!

③:而将一个图片资源放到程序的资源对象树中是用函数QResource::registerResource()来实现的。亦即:要将资源向这颗资源对象树进行注册,这样才对在系统中new创建这个资“叶子”。

对于这一点我们可以直接查看该函数的源码:

bool
       QResource::registerResource(const QString &rccFilename, const QString &resourceRoot)
       {
            QString r = qt_resource_fixResourceRoot(resourceRoot);
            if(!r.isEmpty() && r[0] != QLatin1Char('/'))

{
                 qWarning("QDir::registerResource: Registering a resource [%s] must be rooted in an absolute path (start  with /) [%s]",
                 rccFilename.toLocal8Bit().data(), resourceRoot.toLocal8Bit().data());
                 return false;
            }

 QDynamicFileResourceRoot *root = new QDynamicFileResourceRoot(r);
            if(root->registerSelf(rccFilename))

{
                 root->ref.ref();
                 QMutexLocker lock(resourceMutex());
                 resourceList()->append(root);
                 return true;
            }
           delete root;
           return false;
    }

由上可见:主要就是先创建了一个资源内存对象,而后将其append到资源对象树上。

④:当我们不再使用某个图片资源时:当然希望其不再占用内存,此时需要释放delete它。这时要用QResource::unregisterResource()函数来进行反注册。此函数的作用就是在资源对象树中遍历找到代表该资源的节点,而后delete释放它。源码为:

bool
    QResource::unregisterResource(const QString &rccFilename, const QString &resourceRoot)
    {
          QString r = qt_resource_fixResourceRoot(resourceRoot);

QMutexLocker lock(resourceMutex());
          ResourceList *list = resourceList();
          for(int i = 0; i < list->size(); ++i)

{
               QResourceRoot *res = list->at(i);
               if(res->type() == QResourceRoot::Resource_File)

{
                    QDynamicFileResourceRoot *root = reinterpret_cast<QDynamicFileResourceRoot*>(res);
                     if(root->mappingFile() == rccFilename && root->mappingRoot() == r)

{
                         resourceList()->removeAt(i);
                          if(!root->ref.deref())

{
                              delete root;
                              return true;
                          }
                          return false;
                    }
               }
           }
           return false;
   }

总起来说就是:一个程序所用的所有资源都是放到一颗资源对象树中的,当程序启动时该树便会自动创建,而当我们使用某个资源时:都需要实现将其向该树进行注册,当不需要时则需要进行反注册。

========================================================================

下边说一下我常用的使用图片资源的方式,主要有三种:

1:使用qrc资源文件来加载。

对于这种方式:其是将所有的图片资源都转化成二进制数据,存放在一个静态数组中,而后放到应用程序中。所以:当程序执行时:所有图片都会一直在内存中,这杨虽然读取速度很快,但是很占用内存空间,对于一些内存有限的设备不是很适合。

系统转换的主要步骤为:

①:当编译时,其会将我们写的 name.qrc文件转换生成一个qrc_name.cpp的资源文件,我们可以自己看下这个生成的cpp文件,发现其中就是主要有三个static const数组。

qt_resource_data[]

qt_resource_name[]

qt_resource_struct[]

这其中qt_resource_data[]中存放的就是图片的二进制数据。而后边的两个数组我们猜测是做了一个图片名字到上边数据的映射,方便系统找到data中的二进制数据。

至于内部作用机制,有的资料上说是:当使用qrc资源文件时:系统会自动将所有的图片资源都向程序的资源对象树进行注册,并且当程序结束运行时再进行反注册。这也正好解释了为什么此种方法下图片资源会一直占用内存的原因。

使用这种方法时:由于图片资源一直在内存中,避免了I/O操作,从而加快了读取速度。但是却是以消耗内存为代价的。我做过一个project,因为其中用了大量的图片,结果导致内存使用量超乎想象的大,后来就进行了优化,也就是用了下边提到的第二种方法。

2:手动进行注册。

第一种方法相当于静态加载,但很多情况下我们更希望是动态加载,亦即:用到哪个资源才将该资源加载进来,而不用的则不加载。

上边第一种方法之 所以显示出静态加载的特性,这是由于系统一次性自动把所有图片资源都进行了注册,并且在程序运行过程中一直没有进行反注册才导致的。  如果我们可以自行决定:什么时候对那一部分图片资源进行注册?什么时候对哪一部分图片资源进行反注册。则显然我们可以手动控制整个资源在内存中的生存周 期!!

这种方法的主要步骤为:

①:生成外部二进制资源文件。

②:在需要时将该资源向程序的资源对象树进行注册并使用。

③:在不需要时进行反注册。

步骤①主要是用了Qt自带的一个工具:rcc.exe  (处于bin文件夹中)。这是Qt的一个资源编译器,其编译对象是qrc文件,而生成rcc二进制资源文件。

那我们可以用它来执行命令 rcc -binary name.qrc -o name.rcc  来把qrc资源文件转成rcc二进制资源文件。

而后在程序内部:当需要使用某一图片资源时:则直接调用

QResource::registerResource(“name.rcc”)进行注册创建分配内存即可!  而不使用时候则调用反注册函数!!

--》为了进行验证,我曾经测试了一个例子,主要思路就是:在一个工程中写了一个包含若干幅图片的qrc资源文件,将其转化成rcc二进制资源文件。   我在程序界面上摆放两个按钮button,  其中一个button的click事件响应槽负责调用QResource::registerResource()将这个二进制资源文件注册, 而另外一个button进行反注册。  然后跑一下这个程序,查看下其所占用的内存大小:

刚启动时:程序所占内存显示为:8940K

而后按下第一个button进行注册,此时占用内存为:9276K

最后点一下另外一个button,进行反注册后,其占用内存大小为:8948K

由上测试可见:注册后才会让资源占用内存!!反注册后其会从内存中delete掉!!

所以:这种方式算是动态加载,会少占用内存。但是如果图片过多的话,什么时候需要加载,什么时候需要去掉,这些逻辑就需要十分注意了。

3:直接I/O读取。

比如:  ptr->setStyleSheet("./bmp/name.png");

这种方式我不怎么用,感觉I/O操作速度慢吧,所以一直没去深究。道理上边都有。

Qt中(图片)资源的使用方式的更多相关文章

  1. Vue中图片的加载方式

    一.前言 VUE项目中图片的加载是必须的,那么vue中图片的加载方式有哪些呢,今天博主就抽点时间来为大家大概地捋一捋. 二.图片的加载方法 1.在本地加载图片(静态加载) 图片存放assets文件夹中 ...

  2. 2.QT中使用资源文件,程序打包

     1 程序中使用资源文件 A  一个QT空项目 B  右击项目,添加新文件 添加后的效果是 C  右击main.prc,选择"添加现有项",找到要使用的资源文件.最终的效果是: ...

  3. (转)Qt中图片相对位置的引用

    原文作者:locky1218 原文地址:https://blog.csdn.net/locky1218/article/details/9749703/   一般使用相对位置的时候可能无法显示图片,可 ...

  4. Qt5:Qt中图片的翻转,旋转,缩放,扭曲操作

    具体用到了  mirror()  shear()  scaled() translate() rotate() 等函数函数等会儿再写 (其中  translate() 和 rotate() 俩函数组合 ...

  5. qt中窗口绘制——图片的绘制

    在qt 中,QPixmap 用于表示一张图片,支持png,jpg格式的加载. QPixmap pm("c:/test.png"); 或者 QPixmap pm; pm.load(& ...

  6. Spring Boot 中初始化资源的几种方式(转)

    假设有这么一个需求,要求在项目启动过程中,完成线程池的初始化,加密证书加载等功能,你会怎么做?如果没想好答案,请接着往下看.今天介绍几种在Spring Boot中进行资源初始化的方式,帮助大家解决和回 ...

  7. Spring Boot 中初始化资源的几种方式

    假设有这么一个需求,要求在项目启动过程中,完成线程池的初始化,加密证书加载等功能,你会怎么做?如果没想好答案,请接着往下看.今天介绍几种在Spring Boot中进行资源初始化的方式,帮助大家解决和回 ...

  8. 第32课 Qt中的文件操作

    1. Qt的中IO操作 (1)Qt中IO操作的处理方式 ①Qt通过统一的接口简化了文件和外部设备的操作方式 ②Qt中的文件被看作一种特殊的外部设备 ③Qt中的文件操作与外部设备的操作相同 (2)IO操 ...

  9. Qt中的标准对话框之QMessageBox

    1. Qt标准对话框 Qt为开发者提供了一些可复用的对话框类型 Qt提供的可复用对话框全部继承自QDialog类 Qt中的对话框的使用方式和QDialog完全一致 2. 标准对话框的使用步骤 ①定义对 ...

  10. 通过源码浅析Java中的资源加载

    前提 最近在做一个基础组件项目刚好需要用到JDK中的资源加载,这里说到的资源包括类文件和其他静态资源,刚好需要重新补充一下类加载器和资源加载的相关知识,整理成一篇文章. 理解类的工作原理 这一节主要分 ...

随机推荐

  1. dedecms清空所有文章怎么操作?sql语句如何写?

    小C新建了一个站,确切的说是复制,出于seo考虑,决定清空所有文章,那么dedecms清空所有文章怎么操作?sql语句如何写呢?特别提醒:修改之前一定要先做好备份,以防万一!下面的语句在迫不得已的情况 ...

  2. 电脑出现 flash update failed 解决方法

    笔记本电脑过了一个周末打开时出现以上问题,每次都进入这个界面 解决方法: 拆机,插拨一下内存条,硬盘,就启动了

  3. xshell中alt+.不能用问题

  4. 使用SBT构建Scala应用【转载】

    使用SBT构建Scala应用 SBT简介 SBT是Simple Build Tool的简称,如果读者使用过Maven,那么可以简单将SBT看做是Scala世界的Maven,虽然二者各有优劣,但完成的工 ...

  5. LaTeX使用学习

    LaTeX是什么? 文档结构 标点符号 行内公式$\oint\sqrt{a}$ 行间公式 \begin{equation}\label{a}\oint\sqrt{a}\end{equation}

  6. vue 获取屏幕宽高 width height

    /**  * 获取屏幕宽高  */ Vue.prototype.getViewportSize = function(){   return {     width: window.innerWidt ...

  7. 微信小程序github源码

    https://github.com/justjavac/awesome-wechat-weapp https://www.cnblogs.com/tuyile006/p/6268961.html h ...

  8. 【开发者笔记】python中的类方法(@classmethod)和静态方法(@staticmethod)

    在java.c#等高级语言中我们用static来定义静态方法和静态变量,那么在python中如何定义静态方法和静态变量呢. python提供了@classmethod和@staticmethod来定义 ...

  9. spark提交任务的三种的方法

    在学习Spark过程中,资料中介绍的提交Spark Job的方式主要有三种: 第一种: 通过命令行的方式提交Job,使用spark 自带的spark-submit工具提交,官网和大多数参考资料都是已这 ...

  10. 从原型链看DOM--Node类型

    前言: 本系列从原型,原型链,属性类型等方面下手学习了DOM文档对象模型,旨在弄清我们在DOM中常用的每一个属性和方法都清楚它从哪里来要到哪里做什么事,这样对于理解代码有一定启发.全靠自己在总结中摸索 ...