您的位置:首页 > 其它

一个简单的能显示动态图片的类(一)

2005-02-22 16:05 429 查看
使用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);
 }

这时,算是完成了,只要点击“取消”按钮,就能画出你指定的图片。效果如下
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐