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

使用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);
 }

这时,算是完成了,只要点击“取消”按钮,就能画出你指定的图片。效果如下

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
使用GDI+显示gif动态图片,该接口如下: 可以看出,该ImageEx完全继承了基的接口函数。 说明: 如果打开非多帧图片,该几乎完全等价于基,比如你可以把该的对象代入Graphics系列的成员函数; 如果打开的是多帧的图片,你只要打开图片后不调用InitAnimation函数(它会创建线程),则上述做法依然可以; 但如果调用InitAnimation函数后(单帧图像没关系,因为不会创建线程),则不可以了, 所有的基继承过来的接口成员函数和配合gdi+库其他的函数调用都是不可以的,因为没有作线程同步, 你只能调用下面位数不多的几个public成员函数,调用Destroy成员函数后,则就可以了,因为它会关闭线程。 其实你会发现下面的public成员函数操作的成员变量都是新增的成员变量,没涉及到线程同步问题。 class ImageEx : public Image { public: //以长度为nSize的内存pBuff的内容构造图像 ImageEx(const void* pBuff, size_t nSize, BOOL useEmbeddedColorManagement = FALSE); //以型为sResourceType,名称为sResource的资源构造图像 ImageEx(LPCTSTR sResourceType, LPCTSTR sResource, BOOL useEmbeddedColorManagement = FALSE); //以文件构造图像 ImageEx(LPCTSTR filename, BOOL useEmbeddedColorManagement = FALSE); //调用Destroy成员函数 ~ImageEx(); public: //如果已经构造的对象是动画,则创建动画线程,并返回true, //如果为静态图像或已经创建过动画线程,则也返回false // 图像将绘制在m_hWnd客户区的rect区域,会拉伸,支持镜像 bool InitAnimation(HWND hWnd, RECT rect); //判断是否为动画 bool IsAnimatedGIF() { return m_nFrameCount > 1; } //设置动画暂停与否 void SetPause(bool bPause); //判断动画是否处于暂停状态 bool IsPaused() { return m_bPause; } //关闭动画,事实上基Image还有的两个成员变量没有关闭,因为析构函数会调用基析构函数进行关闭的 void Destroy(); //另外的非public的东西省略.. }; 用法: MFC对话框程序在下面添加: BOOL CTestDlgDlg::OnInitDialog() { CDialog::OnInitDialog(); //其它的初始化代码 // GDI+ //m_imageImageEx指针型成员变量,"GIF"为资源型,"HEARTS"为资源名称 m_image = new ImageEx( _T("GIF"), _T("HEARTS") ); RECT rc; GetClientRect(&rc); m_image->InitAnimation(this->m_hWnd, rc);//创建gif播放线程 return TRUE; // return TRUE unless you set the focus to a control } CTestDlgDlg::~CTestDlgDlg() { // GDI+ delete m_image; } 其的m_image = new ImageEx( _T("GIF"), _T("HEARTS") );你可以换成ImageEx的另外两个构造函数

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值