一、MFC使用GDI+编程设置
(1)增加静态库文件GdiPlus.lib
在VC2005“项目/*属性”菜单项,打开项目的属性页窗口,先选“所有配置”,再选“配置属性/链接器/输入”项。在右边上部的“附加依赖项”栏的右边,键入GdiPlus.lib 后按“应用”钮,最后按“确定”钮关闭对话框。
当然,我们也可以在代码中使用#pragma comment( lib, "gdiplus.lib" )实现对静态文件的引用。
(2)增加GDI+的头文件和命名空间
在需要用到GDI+的文件头加上下面两句
#include <gdiplus.h>
using namespace Gdiplus;
(3)增加成员变量
在应用程序类应用程序类(CGDIPlusDemoApp) 头文件中,声明一个成员ULONG PTR类型的变量:
ULONG_PTR m_gdiplusToken; // ULONG PTR 为int64 类型
(4)初始化操作
在该类的初始化函数CGDIPlusDemoApp::InitInstance() 中
加入以下代码来对GDI+进行初始化:
GdiplusStartupInput gdiplusStartupInput; //声明
GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL); //启动
注意:这两个语句必须加在应用程序类的InitInstance函数中的
CWinApp:: InitInstance ();
语句之前,不然以后会造成视图窗口不能自动重画、程序中不能使用字体等等一系列问题。
(5)关闭GDI+操作
在CGDIPlusDemoApp::ExitInstance() 函数(重写)中加入以下代码来关闭GDI +:
GdiplusShutdown(m_gdiplusToken);//关闭
====================================================
二、MFC使用GDI+编程实例
1、GDI+程序设计步骤:
(1)、在项目中引入GDI+的头文件,使用GDI+的命名空间。
(2)、初始化GDI+系统资源。
(3)、使用完毕之后,释放GDI+所使用的资源。
(4)、在编译时加入GDIplus.Lib库文件。
2、实例步骤:
(1)建立项目
打开Visual C++.NET,在菜单中点击“文件”|“新建”|“项目”,然后建立MFC的“单文档”应用程序,本文建立的项目名称为GDIPlusDemo。
(2)、在程序中使用GDI+命名空间
由于GDI+中使用了自己的命名空间(这可以从GDIplus.h头文件中看出GDI+对命名空间的定义),我们需要引入头文件,还要声明其命名空间,并且添加GDI+运行库(GDIplus.lib)支持。
具体方法是修改stdafx.h文件,在该头文件的结尾处加入下列的代码:
#include <GdiPlus.h> //引入GDI+头文件
using namespace Gdiplus; //使用GDI+的命名空间
#pragma comment( lib, "gdiplus.lib" ) //引入静态库文件
(3)、GDI+资源的初始化与销毁
在使用GDI+的资源之前,我们应该通过GdiplusStartup(启用GDI-资源)函数进行GDI+系统资源的初始化操作;而在程序结束前,我们也应该通过GdiplusShutdown(关闭GDI+资源)函数进行GDI+资源的销毁操作。
这两项工作,分别可以在CGDIPlusDemoApp应用类的InitInstance(初始化进程)函数和CGDIPlusDemoApp类的析构函数中进行。
首先需要在CGDIPlusDemoApp中增加一个全局变量,以表明对GDI+的一个引用,实现的代码如下:
ULONG_PTR gdiplusToken; //全局变量,表明对GDI+的一个引用
在CGDIPlusDemoApp的InitInstance()函数中增加GDI+函数的初始化操作:
BOOL CGDIPlusDemoApp::InitInstance()
{
InitCommonControls();
//GDI+系统资源的初始化
GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup(&gdiplusToken,&gdiplusStartupInput,NULL);
CWinApp::InitInstance(); // GDI+系统资源的初始化的代码需要放在该代码前
// 初始化OLE 库
if (!AfxOleInit())
{
……
}
}
最后,使用完GDI+后在CGDIPlusDemoApp::ExitInstance()函数中将其销毁:
int CGDIPlusDemoApp::ExitInstance()
{
// TODO: 在此添加专用代码和/或调用基类
GdiplusShutdown(gdiplusToken);
return CWinApp::ExitInstance();
}
全局变量gdiplusToken的作用是代表着对GDI+的一个引用。在使用GdiplusStartup函数时,该变量已经被初始化,在使用GdiplusShutdown函数时,通过对该变量gdiplusToken的访问,完成对GDI+资源的销毁工作。
经过上述三个步骤,一个完整的GDI+程序的框架已经搭建完毕,其他只需在CGDIPlusDemoView::OnDraw(CDC* pDC)函数中添加相应的代码就可以了。
====================================================
三、MFC使用GDI+编程基础
封装在GDI+ API中的各种C++类、函数、常量、枚举和结构,都被定义在Gdiplus.h头文件所包含的一系列头文件中。所以,采用MFC进行GDI+编程,必须包含Gdiplus.h头文件。
封装在GDI+类中方法,最后都需要调用GDI+平面API中的相关底层函数,才能完成实际的操作。所以,为了运行GDI+应用程序,在操作系统平台中,必须安装动态链接库Gdiplus.dll。
该动态链接库所对应的静态库文件为GdiPlus.lib,而且它不是C++和MFC的缺省链接库。所以,必须在项目设置,添加该库作为链接器输入的附加依赖项。
因为在Gdiplus.h头文件中,将所有的GDI+的类、函数、常量、枚举和结构等都定义在了命名空间Gdiplus中。所以,一般在GDI+程序中,都必须使用如下的命名空间声明:
using namespace Gdiplus;
例如:
#include <gdiplus.h>
using namespace Gdiplus;
……
1)GdiPlus.h代码
/*********************************************************************/
* Copyright (c) 1998-2001, Microsoft Corp. All Rights Reserved.
* Module Name:
* Gdiplus.h
* Abstract:
* GDI+ public header file
/*********************************************************************/
#ifndef _GDIPLUS_H
#define _GDIPLUS_H
struct IDirectDrawSurface7;
typedef signed short INT16;
typedef unsigned short UINT16;
#include <pshpack8.h> // set structure packing to 8
namespace Gdiplus
{
namespace DllExports {
#include "GdiplusMem.h"
};
#include "GdiplusBase.h"
#include "GdiplusEnums.h"
#include "GdiplusTypes.h"
#include "GdiplusInit.h"
#include "GdiplusPixelFormats.h"
#include "GdiplusColor.h"
#include "GdiplusMetaHeader.h"
#include "GdiplusImaging.h"
#include "GdiplusColorMatrix.h"
#include "GdiplusGpStubs.h"
#include "GdiplusHeaders.h"
namespace DllExports {
#include "GdiplusFlat.h"
};
#include "GdiplusImageAttributes.h"
#include "GdiplusMatrix.h"
#include "GdiplusBrush.h"
#include "GdiplusPen.h"
#include "GdiplusStringFormat.h"
#include "GdiplusPath.h"
#include "GdiplusLineCaps.h"
#include "GdiplusMetafile.h"
#include "GdiplusGraphics.h"
#include "GdiplusCachedBitmap.h"
#include "GdiplusRegion.h"
#include "GdiplusFontCollection.h"
#include "GdiplusFontFamily.h"
#include "GdiplusFont.h"
#include "GdiplusBitmap.h"
#include "GdiplusImageCodec.h"
}; // namespace Gdiplus
#include <poppack.h> // pop structure packing back to previous state
#endif // !_GDIPLUS_HPP
2)GDI+的初始化与清除
为了在MFC应用程序中使用采用C++封装的GDI+ API,我们必须在MFC项目的应用程序类中,调用GDI+命名空间中的GDI+启动函数GdiplusStartup和GDI+关闭函数GdiplusShutdown,来对GDI+进行初始化(装入动态链接库Gdiplus.dll,或锁定标志+1)和清除(卸载动态链接库Gdiplus.dll,或锁定标志-1)工作。它们一般分别在应用程序类的InitInstance和ExitInstance重载成员函数中调用。
函数GdiplusStartup和GdiplusShutdown,都被定义在GdiplusInit.h头文件中:
//GDI+的启动函数
Status WINAPI GdiplusStartup(
OUT ULONG_PTR *token,
const GdiplusStartupInput *input,
OUT GdiplusStartupOutput *output);
//GDI+的关闭函数
void GdiplusShutdown(ULONG_PTR token);
其中:
类型ULONG_PTR,是用无符号长整数表示的指针,被定义在basetsd.h头文件中:
typedef _W64 unsigned long ULONG_PTR;
输出参数token(权标),供关闭GDI+的函数使用,所以必须设置为应用程序类的成员变量(或全局变量,不提倡)。
结构GdiplusStartupInput和GdiplusStartupOutput,也都被定义在GdiplusInit.h头文件中:
struct GdiplusStartupInput
{
UINT32 GdiplusVersion; // Must be 1,必须是1
DebugEventProc DebugEventCallback; // Ignored on free builds,
BOOL SuppressBackgroundThread; // FALSE unless you're prepared to call
// the hook/unhook functions properly
BOOL SuppressExternalCodecs; // FALSE unless you want GDI+ only to use
// its internal image codecs.
GdiplusStartupInput(
DebugEventProc debugEventCallback = NULL,
BOOL suppressBackgroundThread = FALSE,
BOOL suppressExternalCodecs = FALSE)
{
GdiplusVersion = 1;
DebugEventCallback = debugEventCallback;
SuppressBackgroundThread = suppressBackgroundThread;
SuppressExternalCodecs = suppressExternalCodecs;
}
};
struct GdiplusStartupOutput
{
NotificationHookProc NotificationHook;
NotificationUnhookProc NotificationUnhook;
};
GDI+启动输入结构指针参数input,一般取缺省构造值即可,即(设:无调试事件回调过程、不抑制背景线程、不抑制外部编解码):
input = GdiplusStartupInput(NULL, FALSE, FALSE);
GDI+启动输出结构指针参数output,一般不需要,取为NULL即可。
注意,采用MFC进行GDI+ API编程时,在使用任何GDI+的功能调用之前,必须先调用GDI+启动函数GdiplusStartup来进行初始化GDI+的工作;在完成所有的GDI+功能调用之后,必须调用GDI+关闭函数GdiplusShutdown来进行清除GDI+的工作。
例如,创建一个名为GdipDraw的MFC单文档应用程序项目,在项目属性中添加GdiPlus.lib库作为链接器输入的附加依赖项
// GdipDraw.h 头文件
……
class CGdipDrawApp : public CWinApp
{
public:
CGdipDrawApp();
ULONG_PTR m_gdiplusToken;
……
};
// GdipDraw.cpp 实现文件
……
#include <gdiplus.h>
sing namespace Gdiplus;
……
BOOL CGdipDrawApp::InitInstance()
{
// 如果一个运行在 Windows XP 上的应用程序清单指定要
// 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式,
//则需要 InitCommonControlsEx()。否则,将无法创建窗口。
INITCOMMONCONTROLSEX InitCtrls;
InitCtrls.dwSize = sizeof(InitCtrls);
// 将它设置为包括所有要在应用程序中使用的
// 公共控件类。
InitCtrls.dwICC = ICC_WIN95_CLASSES;
InitCommonControlsEx(&InitCtrls);
/*注意:下面这两个语句必须加在CWinApp:: InitInstance ();语句之前,不然以后会造成视图窗口不能自动重画、程序中不能使用字体等等一系列问题。*/
GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
CWinApp::InitInstance();
……
}
……
int CGdipDrawApp::ExitInstance() // 该函数是自己利用属性窗口,添加的重写函数
{
GdiplusShutdown(m_gdiplusToken);
return CWinApp::ExitInstance();
}
3)几何辅助类
在GDI+ 的API中,定义了许多绘图的辅助类,常用的有点、大小和矩形等几何类。它们都是没有基类的独立类,被定义在头文件GdiplusTypes.h中。下面逐个进行介绍:
(1)Point/Point F (点)
GDI+中,有两种类型的点:整数点(对应于Point类)和浮点数点(对应于PointF类)。下面分别加以介绍:
整数点类Point:
class Point {
public:
Point() {X = Y = 0;}
Point(const Point &point) {X = point.X; Y = point.Y;}
Point(const Size &size) {X = size.Width; Y = size.Height;}
Point(INT x, INT y) {X = x; Y = y;}
Point operator+(const Point& point) const {return Point(X + point.X, Y + point.Y);}
Point operator-(const Point& point) const {return Point(X - point.X, Y - point.Y);}
BOOL Equals(const Point& point) {return (X == point.X) && (Y == point.Y);}
public:
INT X; // 大写X、Y
INT Y;
};
其中:
typedef int INT; // 4字节有符号整数(windef.h)
注意,这里的点与GDI的区别:
POINT和CPoint:{x; y;} // 小写x、y
浮点数点类PointF:
class PointF {
public:
PointF() {
X = Y = 0.0f; }
PointF(const PointF &point) {
X = point.X; Y = point.Y; }
PointF(const SizeF &size) {
X = size.Width; Y = size.Height ;}
PointF(REAL x, REAL y) {
X = x; Y = y; }
PointF operator+(const PointF& point) const {
return PointF(X + point.X,Y + point.Y); }
PointF operator-(const PointF& point) const {
return PointF(X - point.X, Y - point.Y); }
BOOL Equals(const PointF& point) {
return (X == point.X) && (Y == point.Y); }
public:
REAL X;
REAL Y;
};
其中:
typedef float REAL; // 4字节浮点数(GdiplusTypes.h)
注意,浮点数版的几何对象和绘图函数,是GDI+新增的功能,这些在各种工程技术领域都非常有用。因为一般的实际图形设计,都是基于实数坐标的。包括机械(机床/汽车/轮船/飞机等)、建筑(房屋/桥梁/道路/堤坝等)和图形动画设计(形状/物体/人物/背景/轨迹等)等设计,都必须使用浮点参数和坐标系。
(2)Size/ SizeF(大小)
GDI+中,也有两种类型的大小(尺寸):整数大小(对应于Size类)和浮点数大小(对应于SizeF类)。下面分别加以介绍:
整数大小类Size:
class Size {
public:
Size() {
Width = Height = 0; }
Size(const Size& size) {
Width = size.Width; Height = size.Height; }
Size(INT width, INT height) {
Width = width; Height = height; }
Size operator+(const Size& sz) const {
return Size(Width + sz.Width, Height + sz.Height); }
Size operator-(const Size& sz) const {
return Size(Width - sz.Width, Height - sz.Height); }
BOOL Equals(const Size& sz) const {
return (Width == sz.Width) && (Height == sz.Height); }
BOOL Empty() const {
return (Width == 0 && Height == 0); }
public:
INT Width; // 不是cx和cy
INT Height;
};
注意,这里的大小与GDI的区别:
SIZE和CSize:{cx; cy;} // 不是宽和高
浮点数大小类SizeF:
class SizeF {
public:
SizeF() {
Width = Height = 0.0f; }
SizeF(const SizeF& size) {
Width = size.Width; Height = size.Height; }
SizeF(REAL width, REAL height) {
Width = width; Height = height; }
SizeF operator+(const SizeF& sz) const {
return SizeF(Width + sz.Width, Height + sz.Height); }
SizeF operator-(const SizeF& sz) const {
return SizeF(Width - sz.Width, Height - sz.Height); }
BOOL Equals(const SizeF& sz) const {
return (Width == sz.Width) && (Height == sz.Height); }
BOOL Empty() const {
return (Width == 0.0f && Height == 0.0f); }
public:
REAL Width;
REAL Height;
};
(3)Rect/ Rect F(矩形)
GDI+中,也有两种类型的矩形:整数矩形(对应于Rect类)和浮点数矩形(对应于RectF类)。下面分别加以介绍:
整数矩形类Rect:
class Rect {
public:
Rect() {X = Y = Width = Height = 0;}
Rect(INT x, INT y, INT width, INT height);
Rect(const Point& location, const Size& size);
Rect* Clone() const;
VOID GetLocation(OUT Point* point) const;
VOID GetSize(OUT Size* size) const;
VOID GetBounds(OUT Rect* rect) const;
INT GetLeft() const {return X;}
INT GetTop() const {return Y;}
INT GetRight() const {return X+Width;}
INT GetBottom() const {return Y+Height;}
BOOL IsEmptyArea() const{return (Width <= 0) || (Height <= 0);}
BOOL Equals(const Rect & rect) const;
BOOL Contains(INT x, INT y) const;
BOOL Contains(const Point& pt) const;
BOOL Contains(Rect& rect) const;
VOID Inflate(INT dx, INT dy) {
X -= dx; Y -= dy;
Width += 2*dx; Height += 2*dy; }
VOID Inflate(const Point& point) {Inflate(point.X, point.Y);}
BOOL Intersect(const Rect& rect) {return Intersect(*this, *this, rect);}
static BOOL Intersect(OUT Rect& c, const Rect& a, const Rect& b);
BOOL IntersectsWith(const Rect& rect) const;
static BOOL Union(OUT Rect& c, const Rect& a, const Rect& b);
VOID Offset(const Point& point);
VOID Offset(INT dx, INT dy);
public:
INT X; // 不是left和top
INT Y;
INT Width; // 更不是right和bottom
INT Height;
};
注意,这里的矩形与GDI的区别:
RECT:{left; top; right; bottom;}; // 不是宽和高
虽然Rect中的(X, Y)等价于RECT的( left, top),但是Rect中的(Width, Height)却不同于RECT的( right, bottom)。
浮点数矩形类RectF:
class RectF {
public:
RectF() {X = Y = Width = Height = 0.0f;}
RectF(REAL x, REAL y, REAL width, REAL height);
RectF(const PointF& location, const SizeF& size);
RectF* Clone() const;
VOID GetLocation(OUT PointF* point) const;
VOID GetSize(OUT SizeF* size) const;
VOID GetBounds(OUT RectF* rect) const;
REAL GetLeft() const;
REAL GetTop() const;
REAL GetRight() const;
REAL GetBottom() const;
BOOL IsEmptyArea() const;
BOOL Equals(const RectF & rect) const;
BOOL Contains(REAL x, REAL y) const;
BOOL Contains(const PointF& pt) const;
BOOL Contains(const RectF& rect) const;
VOID Inflate(REAL dx, REAL dy);
VOID Inflate(const PointF& point);
BOOL Intersect(const RectF& rect);
static BOOL Intersect(OUT RectF& c, const RectF& a, const RectF& b);
BOOL IntersectsWith(const RectF& rect) const;
static BOOL Union(OUT RectF& c, const RectF& a, const RectF& b);
VOID Offset(const PointF& point);
VOID Offset(REAL dx, REAL dy);
public:
REAL X;
REAL Y;
REAL Width;
REAL Height;
};
在GDI的MFC封装中,也有点、大小和矩形的
结构:(windef.h)
typedef struct tagPOINT {LONG x; LONG y;} POINT; // typedef long LONG;
typedef struct tagSIZE {LONG cx; LONG cy;} SIZE;
typedef struct tagRECT {LONG left; LONG top; LONG right; LONG bottom;} RECT;
类:(atltypes.h)
class CPoint : public tagPOINT {
public:
CPoint() throw();
CPoint(int initX, int initY) throw();
……
}
class CSize : public tagSIZE {
public:
CSize() throw();
CSize(int initCX, int initCY) throw();
……
}
class CRect : public tagRECT {
public:
CRect() throw();
CRect(int l, int t, int r, int b) throw();
……
}
可见,这几个类都是从对应的结构派生的。GDI中,之所以有了类还要保留结构,主要是考虑效率和与底层GDI API的兼容。
比较可知,GDI和GDI+都有对应的类,不过GDI+没有对应的结构(但有浮点数版类),而GDI则没有对应的浮点数版类(但却有结构)。
参考资料:
1、http://topic.csdn.net/u/20090301/18/60dacb46-9475-4bc0-a362-b37e84c72ec0.html
2、http://blog.csdn.net/touzani/archive/2007/06/17/1655790.aspx