解决duilib使用zip换肤卡顿的问题(附将资源集成到程序中的操作方法)

简介: 转载请说明原出处,谢谢~~        今天在做单子是,客户要求做换肤功能,为此我专门写了一个换肤函数,并且把各种皮肤资源压缩为各个zip文件来换肤。

转载请说明原出处,谢谢~~

       今天在做单子是,客户要求做换肤功能,为此我专门写了一个换肤函数,并且把各种皮肤资源压缩为各个zip文件来换肤。但是客户反映程序运行缓慢,我测试后发现的确明显可以看出慢了不少。最后发现问题在于把皮肤资源都集成到了zip文件中,程序在刷新界面时会重新从zip文件中读取对应的资源,导致了界面反映卡顿。之前直接把z资源放到目录里或者把zip集成到程序内部,都是没问题的。但是如果要换肤就需要用到zip来压缩资源了。

       duilib的WinImplBase类为我们提供了4种加载资源的方法:


	enum UILIB_RESOURCETYPE
	{
		UILIB_FILE=1,		// 来自磁盘文件
		UILIB_ZIP,		// 来自磁盘zip压缩包
		UILIB_RESOURCE,		// 来自资源
		UILIB_ZIPRESOURCE,	// 来自资源的zip压缩包
	};

       使用磁盘文件是最简单的方法,开发时选择这个方法,但是实际发布程序后为了资源的保密就很少这样做了;使用zip文件也是常用的方法,但是问题就在于资源比较多时界面就有明显卡顿;直接使用资源肯定是快速的,但是这个方法就太繁琐了,需要逐个去处理每个资源,用法见MenuDemo;使用资源的zip压缩包,这个是我最常用的,把资源压缩为zip然后集成到程序中,这样不但可以保密资源,而且不会有卡顿的现象。

     

一、 这里先把使用“资源的zip压缩包”方法说明一下:

        1.让自己的窗体类继承WinImplBase类,并且重写GetSkinFile、GetSkinFolder、GetResourceType、GetResourceID这四个方法

        2.在vs中添加自定义资源,找到自己的zip文件并添加,资源类型填写为“ZIPRES”,得到资源的ID号,比如这里为“IDR_ZIPRES2”

        3.GetSkinFile中返回主窗体的xml文件的名字

        4.GetSkinFolder中返回资源文件所在的目录

        5.GetResourceType中返回资源类型,此时应该写为“return UILIB_ZIPRESOURCE;”

        6.GetResourceID中返回对应的zip资源的ID,例如:“return MAKEINTRESOURCE(IDR_ZIPRES2);”

       7.编译程序,这样就可以使用资源的zip压缩包了。

    (ps:在WinMain函数里只要写一句 CPaintManagerUI::SetInstance(hInstance);代码就够了,不需要其他任何CPaintManagerUI的代码,其他代码WinImplBase会处理的!


二、再说明一下常用的zip文件换肤方法

     使用这种方法来换肤,要求加载资源的方式使用第二种“来自磁盘的zip压缩包”方式,用法我就不说明了,duilib的多数demo都是用这种方法。

     如果要换肤,直接使用如下两句代码就可以了:

   CPaintManagerUI::SetResourceZip(_T("skin2.zip")); // 这里写入新的皮肤包的文件名就行了
   CPaintManagerUI::ReloadSkin();


三、使用“来自资源的zip压缩包”方法换肤

     这样做有两个好处,第一是不会有使用单独zip文件那种卡顿现象,第二是资源文件会相对更安全一些。

     我测试了一下,默认情况下不能让duilib使用这种方法来换肤,原因会在后面给出。接下来直接说明怎么使用这个方法:

     从常用的zip文件换肤方法中可以看出,换肤的关键就是重新设置zip文件,也就是说SetResourceZip是换肤的关键函数,他重新指定了zip文件。这个函数有两个版本,一个是加载文件中的zip,另一个是加载资源中的zip,我们需要的就是第二个版本的SetResourceZip。程序调用ReloadSkin函数后,会通知所有控件去重新加载图片资源,图片资源的加载会通过LoadImage函数,这个函数会根据加载资源类型的不同而去选择从不同的地方去试图找到资源并加载。

      在使用“资源的zip压缩包”方法的前提下,如果要换肤就使用如下函数,函数的参数是新换皮肤的资源ID,比如“IDR_ZIPRES2”,函数实际就是从程序资源中找到对应的皮肤zip文件,并且调用对应的SetResourceZip函数加载资源:


void CFrameWnd::ReloadZipResource(int ID)
{

	HRSRC hResource = ::FindResource(m_PaintManager.GetResourceDll(), MAKEINTRESOURCE(ID), _T("ZIPRES"));
	if( hResource == NULL )
		return ;
	DWORD dwSize = 0;
	HGLOBAL hGlobal = ::LoadResource(m_PaintManager.GetResourceDll(), hResource);
	if( hGlobal == NULL ) 
	{
#if defined(WIN32) && !defined(UNDER_CE)
		::FreeResource(hResource);
#endif
		return ;
	}
	dwSize = ::SizeofResource(m_PaintManager.GetResourceDll(), hResource);
	if( dwSize == 0 )
		return ;

	CPaintManagerUI::SetResourceZip((LPBYTE)::LockResource(hGlobal), dwSize);

#if defined(WIN32) && !defined(UNDER_CE)
	::FreeResource(hResource);
#endif

	CPaintManagerUI::ReloadSkin();
}



           理论上这就应该就可以了,但是实际测试还有问题,后来发现是SetResourceZip函数的定义有些问题:

void CPaintManagerUI::SetResourceZip(LPVOID pVoid, unsigned int len)
{
    if( m_pStrResourceZip == _T("membuffer") ) return;
    if( m_bCachedResourceZip && m_hResourceZip != NULL ) {
        CloseZip((HZIP)m_hResourceZip);
        m_hResourceZip = NULL;
    }
    m_pStrResourceZip = _T("membuffer");
    m_bCachedResourceZip = true;
    if( m_bCachedResourceZip ) 
        m_hResourceZip = (HANDLE)OpenZip(pVoid, len, 3);
}

          可以看到如果使用资源zip文件,那么m_pStrResourceZip变量就会保存_T("membuffer")字符串,当再次调用SetResourceZip函数时,由于第一句代码的判断就会导致函数直接返回,所以这里直接注释掉第一句代码就可以了。

         至此,就可以使用资源中的zip文件来换肤了,两全其美。这里还可以扩展,可以把zip资源都继承到一个dll文件中,然后在加载函数里先加载dll,然后从dll加载资源,这样既可以让皮肤资源独立为文件,加载也快速,并且资源也安全。这个代码很好写,我这里就不提供了。

         如有错误,请在博客留言!


         Redrain   2014.10.16

目录
相关文章
|
4天前
|
分布式计算 DataWorks 数据建模
DataWorks常见问题之如何批量修改集成资源组
DataWorks是阿里云提供的一站式大数据开发与管理平台,支持数据集成、数据开发、数据治理等功能;在本汇总中,我们梳理了DataWorks产品在使用过程中经常遇到的问题及解答,以助用户在数据处理和分析工作中提高效率,降低难度。
42 1
|
4天前
|
分布式计算 DataWorks 安全
DataWorks产品使用合集之DataWorks购买的独享集成资源组退订如何解决
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
35 5
|
4天前
|
存储 DataWorks 数据挖掘
Dataworks 独享资源 独享调度资源、独享数据集成资源、独享数据服务资源 的区别 ?
Dataworks 独享资源 独享调度资源、独享数据集成资源、独享数据服务资源 的区别 ?
41 1
|
4天前
|
PHP
【ripro美化】设计子主题sheji-child素材资源下载站模板(集成后台+无授权+独立运行)
安装教程 第一步:首先对应单个上传替换包里面的文件到ripro原主题里面(单个文件覆盖不是替换整个文件包) 第二步:将下载的sheji-child压缩包上传到/wp-content/themes/直接解压,完成后到后台-外观-启用子主题 后台新建页面 1:页面-新建页面-选择VIP介绍模板,链接填vip 2:页面-新建页面-选择自助申请友链模板,链接填links
14 0
【ripro美化】设计子主题sheji-child素材资源下载站模板(集成后台+无授权+独立运行)
|
4天前
ripro子主题wori-child集成后台美化包(适用于设计素材站+资源下载站等)
新内容如下 1、子主题独立运行,彻底摆脱覆盖原主题文件 2、下载信息插件升级优化 3、细节优化
18 0
ripro子主题wori-child集成后台美化包(适用于设计素材站+资源下载站等)
|
4天前
|
消息中间件 DataWorks 关系型数据库
DataWorks的独享资源数据集成
DataWorks的独享资源数据集成
15 1
|
4天前
|
SQL 分布式计算 DataWorks
DataWorks常见问题之买多了一台独立集成资源组没找到释放入口如何解决
DataWorks是阿里云提供的一站式大数据开发与管理平台,支持数据集成、数据开发、数据治理等功能;在本汇总中,我们梳理了DataWorks产品在使用过程中经常遇到的问题及解答,以助用户在数据处理和分析工作中提高效率,降低难度。
34 7
|
6月前
|
DataWorks 索引
DataWorks现在离线节点手动执行,好慢的,要等好久,用公共集成资源就那么慢嘛?
DataWorks现在离线节点手动执行,好慢的,要等好久,用公共集成资源就那么慢嘛?
26 1
|
9月前
|
编译器 API 开发工具
Baumer工业相机使用BGAPI SDK集成VCXG-124M/51M在C++相机初始化资源报错。
Baumer工业相机使用BGAPI SDK集成VCXG-124M/51M在C++相机初始化资源报错。
69 0
|
9月前
|
开发工具 C++ 计算机视觉
Baumer工业相机使用BGAPI SDK集成VCXG-124M/51M在C++释放资源时内存报错0xC0000005。
Baumer工业相机使用BGAPI SDK集成VCXG-124M/51M在C++释放资源时内存报错0xC0000005。
59 0

热门文章

最新文章