一個簡單的能顯示動態圖片的類(一)

使用MS的GDI+可以大大的簡化圖形程序的開發。在VC6中,使用GDI+需要把GDI+頭文件,LIB文件,和GDIPLUS.DLL文件,把頭文件複製到VC的INCLUDE目錄下,把LIB文件複製到VC的LIB目錄下,然後再把GDIPLUS.DLL複製到系統目錄下(XPSP2和2003已經自帶了,不用複製),在代碼中使用GDI+前,應該包含頭文件,鏈接LIB文件,一般在MFC工程的StdAfx.h中加入如下幾行代碼就行:
#ifndef ULONG_PTR
#define ULONG_PTR unsigned long*
#endif
#pragma comment(lib,"gdiplus.lib")
#include <gdiplus.h>
using namespace Gdiplus;
在應用程序初始化和退出的時候,應該初始化和關閉GDI+庫,有兩個函數可以用:
GdiplusStartupInput  m_gdiplusStartupInput;
ULONG_PTR    m_gdiplusToken;
GdiplusStartup(&m_gdiplusToken, &m_gdiplusStartupInput, NULL);//初始化
GdiplusShutdown(m_gdiplusToken);//關閉
下面是一個我自己寫的能顯示動態和靜態圖片的類,寫此類的目的只是學習GDI+的使用,所以寫得非常的簡單,功能也少,只提供了三個接口。類定義如下:
文件名爲ImageEx.h
class ImageEx : public Image
{
public:
 ImageEx(const WCHAR* filename, BOOL useEmbeddedColorManagement = FALSE); 
 ~ImageEx();
public:

 BOOL IsAnimatedGif();           //判斷是否是動態GIF文件
    long GetFrameTime();   //獲取當前幀應該顯示的時間長度
 void ActiveNextFrame();   //激活下一幀爲應該顯示的幀
protected:

 BOOL TestForAnimatedGIF();     
 void Initialize(); 
 UINT   m_nFrameCount;  //幀數
 UINT   m_nFramePosition;   //當前幀的序號
 BOOL   m_bIsInitialized;   //是否初始化完成
 PropertyItem* m_pPropertyItem;    //屬性項,僅用來測試是否是動態圖片

};

類的實現如下:
//文件名爲ImageEx.cpp
ImageEx::ImageEx(const WCHAR* FileName, BOOL useEmbeddedColorManagement)
 :Image(FileName, useEmbeddedColorManagement)
{
 Initialize();           //初始化
 m_bIsInitialized = true;
 TestForAnimatedGIF();   //檢查是不是GIF動畫
}

ImageEx::~ImageEx()
{
 free(m_pPropertyItem);
 m_pPropertyItem = NULL;
}

void ImageEx::Initialize()
{
 m_nFramePosition = 0;
 m_nFrameCount = 0;
 m_bIsInitialized = false;
 m_pPropertyItem = NULL;
}

BOOL ImageEx::TestForAnimatedGIF()
{
 UINT count = 0;
 count = GetFrameDimensionsCount();       //獲得維數
 GUID* pDimensionIDs = new GUID[count];   //分配維ID數組
 
 // Get the list of frame dimensions from the Image object.
 GetFrameDimensionsList(pDimensionIDs, count);//獲得各維的ID
 
 // Get the number of frames in the first dimension.
 m_nFrameCount = GetFrameCount(&pDimensionIDs[0]);//獲得第一維的幀數
 
 // Assume that the image has a property item of type PropertyItemEquipMake.
 // Get the size of that property item.
 int nSize = GetPropertyItemSize(PropertyTagFrameDelay);//獲得幀延遲項
 
 // Allocate a buffer to receive the property item.
 m_pPropertyItem = (PropertyItem*) malloc(nSize);
 
 GetPropertyItem(PropertyTagFrameDelay, nSize, m_pPropertyItem);
 
 delete  pDimensionIDs;
 
 return m_nFrameCount > 1;
}

BOOL ImageEx::IsAnimatedGif()
{
 return m_nFrameCount > 1;
}

long ImageEx::GetFrameTime()
{
 long lPause = ((long*) m_pPropertyItem->value)[m_nFramePosition] * 10;
 return lPause;
}

void ImageEx::ActiveNextFrame()
{
 if (IsAnimatedGif() == FALSE)
  return;
 
 GUID   pageGuid = FrameDimensionTime;
 SelectActiveFrame(&pageGuid, m_nFramePosition++);  
 
 if (m_nFramePosition == m_nFrameCount)
  m_nFramePosition = 0;
}

類的使用非常簡單,要顯示動態的圖片,應該用計時器來幫助實現,測試可以在一個對話框類中加入如下成員變量:
ImageEx* m_pImg;   //圖像
RECT   m_ImgRect;       //圖像區域
UINT       m_nTimer;        //計時器
對話框的構造函數和析構函數如下:
CImgTestDlg::CImgTestDlg(CWnd* pParent /*=NULL*/)
 : CDialog(CImgTestDlg::IDD, pParent)
{
 //{{AFX_DATA_INIT(CImgTestDlg)
  // NOTE: the ClassWizard will add member initialization here
 //}}AFX_DATA_INIT
 // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
 m_pImg = NULL;
 m_nTimer = 0;
}

CImgTestDlg::~CImgTestDlg()
{
 if (m_pImg != NULL)
 {
  delete m_pImg;
  m_pImg = NULL;
 }
 if( m_nTimer != 0)
 {
  KillTimer(m_nTimer);
 }
}
我將在一個Cancel按鈕函數中裝入圖片並顯示它,這樣,當我們點了Cancel按鈕時,將加載指定的圖片並顯示在我們的對話框中:
void CImgTestDlg::OnCancel()
{
 if (m_pImg != NULL)
 {
  return;
 }
 m_pImg = new ImageEx(L"gx033.gif");
 m_ImgRect.left = 0;
 m_ImgRect.top = 0;
 m_ImgRect.right = m_pImg->GetWidth();
 m_ImgRect.bottom = m_pImg->GetHeight();
 if (m_pImg->IsAnimatedGif())
 {  
  long lFrameTime = m_pImg->GetFrameTime();
  m_nTimer = SetTimer(1, lFrameTime, NULL);
  if (m_nTimer == 0)
  {
   MessageBox("Timer Null");
   return;
  }
 } 
 InvalidateRect(&m_ImgRect, FALSE);
}
爲了讓圖片刷新時不閃爍,在這裏,我們只刷新圖片區域,所以我們不用Invalidate()函數,這樣,而且,InvalidateRectt()的第二個參數一定要設置爲FALSE,否則,一樣會閃爍。

在上面的函數中,我們設置了一個計時器,所以,我們要處理時鐘消息,代碼如下:
void CImgTestDlg::OnTimer(UINT nIDEvent)
{
 // TODO: Add your message handler code here and/or call default
 if (m_pImg != NULL)
 {
  if (!m_pImg->IsAnimatedGif())
  {
   return;
  } 
  m_pImg->ActiveNextFrame();                             //顯示下一幀
  long lFrameTime = m_pImg->GetFrameTime(); //獲得下一幀的顯示時間
  m_nTimer = SetTimer(1, lFrameTime, NULL);  //修改計時器的週期爲下一幀的顯示時間
  InvalidateRect(&m_ImgRect, FALSE);                 //刷新圖片區域
 } 
 CDialog::OnTimer(nIDEvent); 
}

爲了顯示圖片,我們在對話框重畫的時候必須畫上我們的圖片,在對話框的OnPait()函數中,我們加入下面的代碼:
if (m_pImg != NULL)
 {
  CClientDC dc(this);
  Graphics  graphics(dc.m_hDC);  
  Status sta = graphics.DrawImage(m_pImg, 0, 0);
 }

這時,算是完成了,只要點擊“取消”按鈕,就能畫出你指定的圖片。效果如下

發佈了29 篇原創文章 · 獲贊 0 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章