使用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);
}
这时,算是完成了,只要点击“取消”按钮,就能画出你指定的图片。效果如下