转载请说明原出处,谢谢~~:http://blog.csdn.net/zhuhongshu/article/details/42502081

因为项目需要我需要给duilib增加一个gif控件,目前已经有了gif控件有很多版本,我去搜集了一些控件,但是都没有自己满意的。原uilib库中已经有GifAnim控件,但是这个控件给出的控制功能不足,不可以控制播放、暂停、停止。当控件隐藏时也不会停止播放动画,会影响效率。

于是在原GifAnim的基础上做了增强,增加了PlayGif、PauseGif、StopGif函数来控制播放、暂停、停止。增加autoplay属性控制控件初始时是否自动播放。

GifAnim的属性如下:

	<GifAnim parent="Control" notifies="setfocus killfocus timer menu windowinit(root)">
<Attribute name="bkimage" default="" type="STRING" comment="Gif动画图片路径"/>
<Attribute name="autoplay" default="true" type="BOOL" comment="是否自动播放GIF动画"/>
<Attribute name="autosize" default="false" type="BOOL" comment="是否根据图片自动设置控件大小"/>
</GifAnim>

xml代码对应为:

         <GifAnim name="gif" bkimage="0.gif" autoplay="true" autosize="true" width="100" height="100" />

gif控件用gdi+函数来解析图片,所以要初始化gdi+接口,为了避免多次重复初始化gdi+,所以把初始化函数写到了CPaintManager的构造函数里。

UIGifAnim.h源码如下:

#ifndef GifAnimUI_h__
#define GifAnimUI_h__ #pragma once namespace DuiLib
{
class CControl; #define EVENT_TIEM_ID 100 class UILIB_API CGifAnimUI : public CControlUI
{
public:
CGifAnimUI(void);
~CGifAnimUI(void); LPCTSTR GetClass() const;
LPVOID GetInterface(LPCTSTR pstrName);
void DoInit() override;
void DoPaint(HDC hDC, const RECT& rcPaint) override;
void DoEvent(TEventUI& event) override;
void SetVisible(bool bVisible = true ) override;
void SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue) override;
void SetBkImage(LPCTSTR pStrImage);
LPCTSTR GetBkImage(); void SetAutoPlay(bool bIsAuto = true );
bool IsAutoPlay() const;
void SetAutoSize(bool bIsAuto = true );
bool IsAutoSize() const;
void PlayGif();
void PauseGif();
void StopGif(); private:
void InitGifImage();
void DeleteGif();
void OnTimer( UINT_PTR idEvent );
void DrawFrame( HDC hDC ); // 绘制GIF每帧
Gdiplus::Image* LoadGifFromFile(LPCTSTR pstrGifPath);
Gdiplus::Image* LoadGifFromMemory( LPVOID pBuf,size_t dwSize );
private:
Gdiplus::Image *m_pGifImage;
UINT m_nFrameCount; // gif图片总帧数
UINT m_nFramePosition; // 当前放到第几帧
Gdiplus::PropertyItem* m_pPropertyItem; // 帧与帧之间间隔时间 CDuiString m_sBkImage;
bool m_bIsAutoPlay; // 是否自动播放gif
bool m_bIsAutoSize; // 是否自动根据图片设置大小
bool m_bIsPlaying; };
} #endif // GifAnimUI_h__

UIGifAnim.cpp源码如下:

#include "StdAfx.h"
#include "UIGifAnim.h" ///////////////////////////////////////////////////////////////////////////////////////
DECLARE_HANDLE(HZIP); // An HZIP identifies a zip file that has been opened
typedef DWORD ZRESULT;
typedef struct
{
int index; // index of this file within the zip
char name[MAX_PATH]; // filename within the zip
DWORD attr; // attributes, as in GetFileAttributes.
FILETIME atime,ctime,mtime;// access, create, modify filetimes
long comp_size; // sizes of item, compressed and uncompressed. These
long unc_size; // may be -1 if not yet known (e.g. being streamed in)
} ZIPENTRY;
typedef struct
{
int index; // index of this file within the zip
TCHAR name[MAX_PATH]; // filename within the zip
DWORD attr; // attributes, as in GetFileAttributes.
FILETIME atime,ctime,mtime;// access, create, modify filetimes
long comp_size; // sizes of item, compressed and uncompressed. These
long unc_size; // may be -1 if not yet known (e.g. being streamed in)
} ZIPENTRYW;
#define OpenZip OpenZipU
#define CloseZip(hz) CloseZipU(hz)
extern HZIP OpenZipU(void *z,unsigned int len,DWORD flags);
extern ZRESULT CloseZipU(HZIP hz);
#ifdef _UNICODE
#define ZIPENTRY ZIPENTRYW
#define GetZipItem GetZipItemW
#define FindZipItem FindZipItemW
#else
#define GetZipItem GetZipItemA
#define FindZipItem FindZipItemA
#endif
extern ZRESULT GetZipItemA(HZIP hz, int index, ZIPENTRY *ze);
extern ZRESULT GetZipItemW(HZIP hz, int index, ZIPENTRYW *ze);
extern ZRESULT FindZipItemA(HZIP hz, const TCHAR *name, bool ic, int *index, ZIPENTRY *ze);
extern ZRESULT FindZipItemW(HZIP hz, const TCHAR *name, bool ic, int *index, ZIPENTRYW *ze);
extern ZRESULT UnzipItem(HZIP hz, int index, void *dst, unsigned int len, DWORD flags);
/////////////////////////////////////////////////////////////////////////////////////// namespace DuiLib
{ CGifAnimUI::CGifAnimUI(void)
{
m_pGifImage = NULL;
m_pPropertyItem = NULL;
m_nFrameCount = 0;
m_nFramePosition = 0;
m_bIsAutoPlay = true;
m_bIsAutoSize = false;
m_bIsPlaying = false; } CGifAnimUI::~CGifAnimUI(void)
{
DeleteGif();
m_pManager->KillTimer( this, EVENT_TIEM_ID ); } LPCTSTR CGifAnimUI::GetClass() const
{
return _T("GifAnimUI");
} LPVOID CGifAnimUI::GetInterface( LPCTSTR pstrName )
{
if( _tcscmp(pstrName, DUI_CTR_GIFANIM) == 0 ) return static_cast<CGifAnimUI*>(this);
return CControlUI::GetInterface(pstrName);
} void CGifAnimUI::DoInit()
{
InitGifImage();
} void CGifAnimUI::DoPaint( HDC hDC, const RECT& rcPaint )
{
if( !::IntersectRect( &m_rcPaint, &rcPaint, &m_rcItem ) ) return;
if ( NULL == m_pGifImage )
{
InitGifImage();
}
DrawFrame( hDC );
} void CGifAnimUI::DoEvent( TEventUI& event )
{
if( event.Type == UIEVENT_TIMER )
OnTimer( (UINT_PTR)event.wParam );
} void CGifAnimUI::SetVisible(bool bVisible /* = true */)
{
CControlUI::SetVisible(bVisible);
if (bVisible)
PlayGif();
else
StopGif();
} void CGifAnimUI::SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue)
{
if( _tcscmp(pstrName, _T("bkimage")) == 0 ) SetBkImage(pstrValue);
else if( _tcscmp(pstrName, _T("autoplay")) == 0 ) {
SetAutoPlay(_tcscmp(pstrValue, _T("true")) == 0);
}
else if( _tcscmp(pstrName, _T("autosize")) == 0 ) {
SetAutoSize(_tcscmp(pstrValue, _T("true")) == 0);
}
else
CControlUI::SetAttribute(pstrName, pstrValue);
} void CGifAnimUI::SetBkImage(LPCTSTR pStrImage)
{
if( m_sBkImage == pStrImage || NULL == pStrImage) return; m_sBkImage = pStrImage; StopGif();
DeleteGif(); Invalidate(); } LPCTSTR CGifAnimUI::GetBkImage()
{
return m_sBkImage.GetData();
} void CGifAnimUI::SetAutoPlay(bool bIsAuto)
{
m_bIsAutoPlay = bIsAuto;
} bool CGifAnimUI::IsAutoPlay() const
{
return m_bIsAutoPlay;
} void CGifAnimUI::SetAutoSize(bool bIsAuto)
{
m_bIsAutoSize = bIsAuto;
} bool CGifAnimUI::IsAutoSize() const
{
return m_bIsAutoSize;
} void CGifAnimUI::PlayGif()
{
if (m_bIsPlaying || m_pGifImage == NULL)
{
return;
} long lPause = ((long*) m_pPropertyItem->value)[m_nFramePosition] * 10;
if ( lPause == 0 ) lPause = 100;
m_pManager->SetTimer( this, EVENT_TIEM_ID, lPause ); m_bIsPlaying = true;
} void CGifAnimUI::PauseGif()
{
if (!m_bIsPlaying || m_pGifImage == NULL)
{
return;
} m_pManager->KillTimer(this, EVENT_TIEM_ID);
this->Invalidate();
m_bIsPlaying = false;
} void CGifAnimUI::StopGif()
{
if (!m_bIsPlaying)
{
return;
} m_pManager->KillTimer(this, EVENT_TIEM_ID);
m_nFramePosition = 0;
this->Invalidate();
m_bIsPlaying = false;
} void CGifAnimUI::InitGifImage()
{
m_pGifImage = LoadGifFromFile(GetBkImage());
if ( NULL == m_pGifImage ) return;
UINT nCount = 0;
nCount = m_pGifImage->GetFrameDimensionsCount();
GUID* pDimensionIDs = new GUID[ nCount ];
m_pGifImage->GetFrameDimensionsList( pDimensionIDs, nCount );
m_nFrameCount = m_pGifImage->GetFrameCount( &pDimensionIDs[0] );
int nSize = m_pGifImage->GetPropertyItemSize( PropertyTagFrameDelay );
m_pPropertyItem = (Gdiplus::PropertyItem*) malloc( nSize );
m_pGifImage->GetPropertyItem( PropertyTagFrameDelay, nSize, m_pPropertyItem );
delete pDimensionIDs;
pDimensionIDs = NULL; if (m_bIsAutoSize)
{
SetFixedWidth(m_pGifImage->GetWidth());
SetFixedHeight(m_pGifImage->GetHeight());
}
if (m_bIsAutoPlay)
{
PlayGif();
}
} void CGifAnimUI::DeleteGif()
{
if ( m_pGifImage != NULL )
{
delete m_pGifImage;
m_pGifImage = NULL;
} if ( m_pPropertyItem != NULL )
{
free( m_pPropertyItem );
m_pPropertyItem = NULL;
}
m_nFrameCount = 0;
m_nFramePosition = 0;
} void CGifAnimUI::OnTimer( UINT_PTR idEvent )
{
if ( idEvent != EVENT_TIEM_ID )
return;
m_pManager->KillTimer( this, EVENT_TIEM_ID );
this->Invalidate(); m_nFramePosition = (++m_nFramePosition) % m_nFrameCount; long lPause = ((long*) m_pPropertyItem->value)[m_nFramePosition] * 10;
if ( lPause == 0 ) lPause = 100;
m_pManager->SetTimer( this, EVENT_TIEM_ID, lPause );
} void CGifAnimUI::DrawFrame( HDC hDC )
{
if ( NULL == hDC || NULL == m_pGifImage ) return;
GUID pageGuid = Gdiplus::FrameDimensionTime;
Gdiplus::Graphics graphics( hDC );
graphics.DrawImage( m_pGifImage, m_rcItem.left, m_rcItem.top, m_rcItem.right-m_rcItem.left, m_rcItem.bottom-m_rcItem.top );
m_pGifImage->SelectActiveFrame( &pageGuid, m_nFramePosition );
} Gdiplus::Image* CGifAnimUI::LoadGifFromFile(LPCTSTR pstrGifPath)
{
LPBYTE pData = NULL;
DWORD dwSize = 0; do
{
CDuiString sFile = CPaintManagerUI::GetResourcePath();
if( CPaintManagerUI::GetResourceZip().IsEmpty() ) {
sFile += pstrGifPath;
HANDLE hFile = ::CreateFile(sFile.GetData(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, \
FILE_ATTRIBUTE_NORMAL, NULL);
if( hFile == INVALID_HANDLE_VALUE ) break;
dwSize = ::GetFileSize(hFile, NULL);
if( dwSize == 0 ) break; DWORD dwRead = 0;
pData = new BYTE[ dwSize ];
::ReadFile( hFile, pData, dwSize, &dwRead, NULL );
::CloseHandle( hFile ); if( dwRead != dwSize ) {
delete[] pData;
pData = NULL;
break;
}
}
else {
sFile += CPaintManagerUI::GetResourceZip();
HZIP hz = NULL;
if( CPaintManagerUI::IsCachedResourceZip() ) hz = (HZIP)CPaintManagerUI::GetResourceZipHandle();
else hz = OpenZip((void*)sFile.GetData(), 0, 2);
if( hz == NULL ) break;
ZIPENTRY ze;
int i;
if( FindZipItem(hz, pstrGifPath, true, &i, &ze) != 0 ) break;
dwSize = ze.unc_size;
if( dwSize == 0 ) break;
pData = new BYTE[ dwSize ];
int res = UnzipItem(hz, i, pData, dwSize, 3);
if( res != 0x00000000 && res != 0x00000600) {
delete[] pData;
pData = NULL;
if( !CPaintManagerUI::IsCachedResourceZip() ) CloseZip(hz);
break;
}
if( !CPaintManagerUI::IsCachedResourceZip() ) CloseZip(hz);
} } while (0); while (!pData)
{
//读不到图片, 则直接去读取bitmap.m_lpstr指向的路径
HANDLE hFile = ::CreateFile(pstrGifPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, \
FILE_ATTRIBUTE_NORMAL, NULL);
if( hFile == INVALID_HANDLE_VALUE ) break;
dwSize = ::GetFileSize(hFile, NULL);
if( dwSize == 0 ) break; DWORD dwRead = 0;
pData = new BYTE[ dwSize ];
::ReadFile( hFile, pData, dwSize, &dwRead, NULL );
::CloseHandle( hFile ); if( dwRead != dwSize ) {
delete[] pData;
pData = NULL;
}
break;
}
if (!pData)
{
return NULL;
} return LoadGifFromMemory(pData, dwSize);
} Gdiplus::Image* CGifAnimUI::LoadGifFromMemory( LPVOID pBuf,size_t dwSize )
{
HGLOBAL hMem = ::GlobalAlloc(GMEM_FIXED, dwSize);
BYTE* pMem = (BYTE*)::GlobalLock(hMem); memcpy(pMem, pBuf, dwSize); IStream* pStm = NULL;
::CreateStreamOnHGlobal(hMem, TRUE, &pStm);
Gdiplus::Image *pImg = Gdiplus::Image::FromStream(pStm);
if(!pImg || pImg->GetLastStatus() != Gdiplus::Ok)
{
pStm->Release();
::GlobalUnlock(hMem);
return 0;
}
return pImg;
} }

总结:

Gif控件已经同步更新到我的duilib库里:点击打开链接

   Redrain  2015.1.7

duilib 增加gif控件(基于gdi+,可控制播放暂停,自动设置大小)的更多相关文章

  1. 将webkit内核封装为duilib的浏览器控件

    转载请说明出处,谢谢~~ 原本的duilib是自带浏览器控件的,但是使用了IE内核,我在做仿酷狗音乐播放器时,在右侧乐库要用到浏览器控件,而我使用自带的IE控件却发现了不少缺点,这也是duilib一直 ...

  2. 改进duilib的richedit控件的部分功能

    转载请说明原出处,谢谢~~:http://blog.csdn.net/zhuhongshu/article/details/41208207 如果要使用透明异形窗体功能,首先要改进duilib库让他本 ...

  3. duilib修复ActiveXUI控件bug,以支持flash透明动态背景

    转载请说明原出处,谢谢~~ 昨天在QQ控件里和同学说起QQ2013登陆窗体的开发,从界面角度考虑,单单一个登陆界面是很容易做出来的.腾讯公司为了 防止各种盗号行为可谓煞费苦心,QQ2013采用了动态背 ...

  4. 五种情况下会刷新控件状态(刷新所有子FWinControls的显示)——从DFM读取数据时、新增加子控件时、重新创建当前控件的句柄时、设置父控件时、显示状态被改变时

    五种情况下会刷新控件状态(刷新控件状态才能刷新所有子FWinControls的显示): 在TWinControls.PaintControls中,对所有FWinControls只是重绘了边框,而没有整 ...

  5. fastscript增加三方控件之二

    fastscript增加三方控件之二 unit fs_BsDataSet; interface {$i fs.inc} uses SysUtils, Classes, fs_iinterpreter, ...

  6. fastscript增加三方控件

    fastscript增加三方控件 A.关于如何使用第三方控件,增加方法.属性.事件)举例如下: 如:有一控件为edtbutton:TedtButton,我们需要在动态脚本中使用该控件.我们采用如下方法 ...

  7. WinForm容器内控件批量效验是否允许为空?设置是否只读?设置是否可用等方法分享

    WinForm容器内控件批量效验是否允许为空?设置是否只读?设置是否可用等方法分享 在WinForm程序中,我们有时需要对某容器内的所有控件做批量操作.如批量判断是否允许为空?批量设置为只读.批量设置 ...

  8. 设置EditText控件中提示消息hint的字体颜色和大小

    设置EditText控件中提示消息hint的字体颜色和大小 1.设置字体大小 代码例: public void init(){ hint= (EditText) findViewById(R.id.i ...

  9. android--------自定义视频控件(视频全屏竖屏自动切换)

    android播放视频也是常用的技术,今天分享一个自定义视频控件,支持自定义控制 UI,全屏播放, 可以实现自动横竖屏切换的控件,跟随手机的位置而,重力感应自动切换横竖屏. 效果图:   代码下载Gi ...

随机推荐

  1. win7重装系统后设置Python2.7环境

    起因 台式机的主板莫名出现问题,显示器画面卡顿不能动,鼠标键盘无反应,在这种情况下只好按住电源键断电.下面重启后,显示器无画面,猜测开机后没有进BIOS.然后就拆机箱,拔下电源线后撬起主板电池几秒再放 ...

  2. linux同步软件

    linux同步软件:scp,rsync,inotify,sersync 1.scp: scp就是secure copy,是用来进行远程文件拷贝的.数据传输使用 ssh,并且和ssh 使用相同的认证方式 ...

  3. [转]Zookeeper系列(一)

    一.ZooKeeper的背景 1.1 认识ZooKeeper ZooKeeper---译名为“动物园管理员”.动物园里当然有好多的动物,游客可以根据动物园提供的向导图到不同的场馆观赏各种类型的动物,而 ...

  4. JS加密库

    作者声明:本博客中所写的文章,都是博主自学过程的笔记,参考了很多的学习资料,学习资料和笔记会注明出处,所有的内容都以交流学习为主.有不正确的地方,欢迎批评指正 本文主要是参考aicoder马伦老师的博 ...

  5. Flip the Bits(思维)

    You are given a positive integer n. Your task is to build a number m by flipping the minimum number ...

  6. 软件工程第七周psp

    1.PSP表格 类别 任务 开始时间 结束时间 中断时间 delta时间 立会 汇报昨天的成绩,分配任务,部署计划 10月27日18:00 10月27日18:36 0 36分钟 准备工作 查阅有关资料 ...

  7. 运维工程师如果将web服务http专变为https

    1:生成私钥   2:生成证书签署请求   3:在提供CA签署的web网站上,提交生成的证书签署请求   4:下载已经签署的CA证书   5:将证书的信息保留在web服务器中,且应用到提供web服务的 ...

  8. huawei oceanstor

      华为产品:OceanStor 6000 V3系列 OceanStor 6800 V3 网页登入设备页面:https+ip+端口 资源分配界面: 首页: wwn为2100xxxxxxxx47e4,设 ...

  9. 201621123037 《Java程序设计》第11周学习总结

    作业11-多线程 标签(空格分隔): Java 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常相关内容. 2. 书面作业 本次PTA作业题集多线程 1. 源代码阅读:多线程程 ...

  10. PHP中与类有关的运算符

    与类有关的运算符: new, instanceof:判断一个“变量”(对象,数据),是否是某个类的“实例”: 示意如下: class  A {} class  B {} class  C extend ...