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

今天在做单子是,客户要求做换肤功能,为此我专门写了一个换肤函数,并且把各种皮肤资源压缩为各个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 ;
m_lpResourceZIPBuffer = new BYTE[ dwSize ];
if (m_lpResourceZIPBuffer != NULL)
{
::CopyMemory(m_lpResourceZIPBuffer, (LPBYTE)::LockResource(hGlobal), dwSize);
}
#if defined(WIN32) && !defined(UNDER_CE)
::FreeResource(hResource);
#endif
CPaintManagerUI::SetResourceZip(m_lpResourceZIPBuffer, dwSize); 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

解决duilib使用zip换肤卡顿的问题:修改duilib并使用资源文件换肤的更多相关文章

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

    转载请说明原出处,谢谢~~ 今天在做单子是.客户要求做换肤功能,为此我专门写了一个换肤函数,而且把各种皮肤资源压缩为各个zip文件来换肤.可是客户反映程序执行缓慢,我測试后发现的确明显能够看出慢了不少 ...

  2. 解决MyEclipse启动慢,使用卡顿问题

    卡顿原因: 1.启动的服务和插件过多,导致启动和运行缓慢,电脑配置较差的直接会卡死没有响应 2.软件运行内存设置不足,导致没有足够的空间运行软件,致使软件卡顿 解决方法: windows --> ...

  3. Android ListView只加载当前屏幕内的图片(解决list滑动时加载卡顿)

    最近在做ListView分页显示,其中包括图片 和文字(先下载解析文字内容,再异步加载图片)发现每次点击下一页后,文字内容加载完毕,马上向下滑动,由于这时后台在用线程池异步下载图片,我每页有20条,也 ...

  4. 解决Mac下AndroidStudio内容时卡顿

    Mac下AndroidStudio在写代码的时候出现卡顿,小圆圈会一直转,此时我们应该检查下AndroidStudio的内存使用情况了. 1.点击左上角 AndroidStudio -- Prefer ...

  5. 解决无法安装cnpm,cnpm卡顿问题

    # 注册模块镜像 npm set registry https://registry.npm.taobao.org # node-gyp 编译依赖的 node 源码镜像 npm set disturl ...

  6. 解决windows 1903 alt + tab 切换卡顿

    右击此电脑图标 选择管理 服务和应用程序 服务 禁用system interface foundation service

  7. 解决页面使用overflow: scroll,overflow-y:hidden在iOS上滑动卡顿的问题

    解决页面使用overflow: scroll,overflow-y:hidden在iOS上滑动卡顿的问题 div{ width: 100%; overflow-y: hidden; -webkit-o ...

  8. 解决eclipse 保存卡顿的问题

    开发十年,就只剩下这套Java开发体系了 >>>   eclipse 如果启动慢,还可以接收. 可是如果是 保存的时候卡顿, 有时候会 卡顿 3秒-5 秒的,感觉到写代码特别的不顺畅 ...

  9. 【转】iOS实时卡顿监控

    转自http://www.tanhao.me/code/151113.html/ 在移动设备上开发软件,性能一直是我们最为关心的话题之一,我们作为程序员除了需要努力提高代码质量之外,及时发现和监控软件 ...

随机推荐

  1. linux入门教程(八) Linux磁盘管理

    [查看磁盘或者目录的容量 df 和 du] df 查看已挂载磁盘的总容量.使用容量.剩余容量等,可以不加任何参数,默认是按k为单位显示的 df常用参数有 –i -h -k –m等 -i 使用inode ...

  2. hdu 1002 A+B

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=1002 复习一下大数 模板: #include <stdio.h> #include <s ...

  3. Spring 3.0: Unable to locate Spring NamespaceHandler for XML schema namespace

    被这个问题折磨着很久:参考: http://have23.iteye.com/blog/1340777 (cfx 与 spring 整合的时候出现的问题: org.springframework.be ...

  4. CSS中nth-child和nth-of-type的简单使用

    ele:nth-child是查找父元素下的子元素,包括子元素类型非ele的,当子元素类型不是ele时,则不会进行任何操作: ele:nth-of-type是查找父元素下的子元素类型为ele的元素,其是 ...

  5. Android中ExpandableListView,每次只展示一个分组

    // 只允许打开一个分组 expandListView.setOnGroupExpandListener(new OnGroupExpandListener() { @Override public ...

  6. JavaScript中样式,方法 函数的应用

    JavaScript中一个字母都不能错,编写的时候他不报错,也不提示,只有在执行的时候才会提示错误位置 . 一.样式 .waring {background-color:yellow } .highl ...

  7. 253. Meeting Rooms II

    题目: Given an array of meeting time intervals consisting of start and end times [[s1,e1],[s2,e2],...] ...

  8. Java根据html模板创建 html文件

    1.创建html的java代码 package com.tydic.eshop.util; import java.io.FileInputStream; import java.io.FileOut ...

  9. 【设计模式】—— 单例模式Singleton

    前言:[模式总览]——————————by xingoo 模式意图 保证类仅有一个实例,并且可以供应用程序全局使用.为了保证这一点,就需要这个类自己创建自己的对象,并且对外有公开的调用方法. 模式结构 ...

  10. jetty ZipException: invalid entry size

    The issue, as I suspected, was due a corrupt JAR file. The solution for me was to clear my local rep ...