c++编写gif动画现实控件
gif.h
class CGIFImage : public CStatic{// Constructionpublic:CGIFImage();void LoadGIF(WCHAR *);void Pause();void Resume();int m_state;// Attributesprivate:struct _sTHPar {Image *m_Img;PropertyItem *m_item;int m_Count;HWND m_hWnd;}sThPar;Image *m_Img;DWORD m_ThreadId;public:// Operationspublic:// Overrides// ClassWizard generated virtual function overrides//{{AFX_VIRTUAL(CGIFImage)//}}AFX_VIRTUAL// Implementationpublic:virtual ~CGIFImage();// Generated message map functionsprotected://{{AFX_MSG(CGIFImage)afx_msg void OnPaint();//}}AFX_MSGstatic DWORD WINAPI DrawGIF(LPVOID);DECLARE_MESSAGE_MAP()};
gif.cpp
CGIFImage::CGIFImage(){m_ThreadId=0;m_Img=0;m_state=-1;}CGIFImage::~CGIFImage(){if(m_ThreadId){::PostThreadMessage(m_ThreadId,WM_GIFSTOP,0,0);}}BEGIN_MESSAGE_MAP(CGIFImage, CStatic)//{{AFX_MSG_MAP(CGIFImage)ON_WM_PAINT()//}}AFX_MSG_MAPEND_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////// CGIFImage message handlersvoid CGIFImage::OnPaint() {CPaintDC dc(this); // device context for painting// TODO: Add your message handler code hereif(m_ThreadId && m_Img){RECT rWin;GetClientRect(&rWin); RectF rF(rWin.left,rWin.top,rWin.right,rWin.bottom);Graphics gh(dc.m_hDC); gh.DrawImage(m_Img,rF,0,0,m_Img->GetWidth(),m_Img->GetHeight(),UnitPixel); }// Do not call CStatic::OnPaint() for painting messages}void CGIFImage::LoadGIF(WCHAR *wzFile){if(m_ThreadId){::PostThreadMessage(m_ThreadId,WM_GIFSTOP,0,0);}m_Img=Image::FromFile(wzFile,FALSE);UINT count=m_Img->GetFrameDimensionsCount();GUID *pDimensionIDs=(GUID*)new GUID[count]; m_Img->GetFrameDimensionsList(pDimensionIDs, count); WCHAR strGuid[39]; StringFromGUID2(pDimensionIDs[0], strGuid, 39); UINT frameCount=m_Img->GetFrameCount(&pDimensionIDs[0]); delete []pDimensionIDs; UINT FrameDelayNums=m_Img->GetPropertyItemSize(PropertyTagFrameDelay); PropertyItem * lpPropertyItem=new PropertyItem[FrameDelayNums]; m_Img->GetPropertyItem(PropertyTagFrameDelay,FrameDelayNums,lpPropertyItem); _sTHPar *sP=new _sTHPar ;sP->m_hWnd=m_hWnd;sP->m_Img=m_Img;sP->m_Count=frameCount;sP->m_item=lpPropertyItem;CreateThread(0,0,DrawGIF,sP,0,&m_ThreadId);m_state=1;}DWORD WINAPI CGIFImage::DrawGIF(LPVOID l){_sTHPar *par=(_sTHPar*)l;int FrameCount=0;long lPause=0;HDC dc=::GetWindowDC(par->m_hWnd);RECT rWin;::GetClientRect(par->m_hWnd,&rWin);RectF rF(rWin.left,rWin.top,rWin.right,rWin.bottom);GUID Guid = FrameDimensionTime; par->m_Img->SelectActiveFrame(&Guid,FrameCount); Graphics gh(dc); gh.DrawImage(par->m_Img,rF,0,0,par->m_Img->GetWidth(),par->m_Img->GetHeight(),UnitPixel); DWORD dTick=GetTickCount();lPause = ((long*)par->m_item->value)[FrameCount]*10; while(1){Sleep(1);MSG msg;if(PeekMessage(&msg,0,0,0,PM_REMOVE)){if(msg.message==WM_GIFSTOP){::ReleaseDC(par->m_hWnd,dc);delete par->m_Img;delete[] par->m_item;delete par;return 0;}}else{if(par->m_Count>1){if(GetTickCount()-dTick>=lPause){if ((FrameCount+1)==par->m_Count) { FrameCount=0; par->m_Img->SelectActiveFrame(&Guid,0); } else { par->m_Img->SelectActiveFrame(&Guid,++FrameCount); } Graphics gh(dc); gh.DrawImage(par->m_Img,rF,0,0,par->m_Img->GetWidth(),par->m_Img->GetHeight(),UnitPixel); lPause = ((long*)par->m_item->value)[FrameCount]*10; dTick=GetTickCount();}}}}return 0;}void CGIFImage::Pause(){if(m_ThreadId){typedef HANDLE (WINAPI *OPENTHREAD) (DWORD , BOOL , DWORD ); OPENTHREAD lpfnOpenThread = (OPENTHREAD)GetProcAddress(LoadLibrary("kernel32.dll"),"OpenThread"); HANDLE hThread = lpfnOpenThread(THREAD_ALL_ACCESS, FALSE, m_ThreadId);SuspendThread(hThread);m_state=0;}}void CGIFImage::Resume(){if(m_ThreadId){typedef HANDLE (WINAPI *OPENTHREAD) (DWORD , BOOL , DWORD ); OPENTHREAD lpfnOpenThread = (OPENTHREAD)GetProcAddress(LoadLibrary("kernel32.dll"),"OpenThread"); HANDLE hThread = lpfnOpenThread(THREAD_ALL_ACCESS, FALSE, m_ThreadId);ResumeThread(hThread);m_state=1;}}
该控件继承cstatic,用gdi+和多线程实现,在多线程里实现gif动画的绘制,这样不闪不卡,实时高效。
文章有不足之处,还望大家多多指正。