使用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);
}
這時,算是完成了,只要點擊“取消”按鈕,就能畫出你指定的圖片。效果如下