2024年1月15日发(作者:)

MFC使用GDI+编程设置

VC2005“项目/*属性”菜单项,打开项目的属性页窗口,先选“所有配置”,再选“配置属性/链接器/输入”项,在右边上部的“附加依赖项”栏的右边,键入 后按“应用”钮,最后按“确定”钮关闭对话框。

在需要用到GDI+的文件头加上下面两句

#include

using namespace Gdiplus;

在应用程序类应用程序类(CGDIPlusDemoApp) 头文件中声明一个成员变量:

ULONG_PTR m_gdiplusToken; // ULONG PTR 为int64 类型

并在该类的初始化函数CGDIPlusDemoApp::InitInstance() 中加入以下代码来对GDI+进行初始化:

GdiplusStartupInput gdiplusStartupInput;

GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);

注意:这两个语句必须加在应用程序类的InitInstance函数中的

CWinApp:: InitInstance ();

语句之前,不然以后会造成视图窗口不能自动重画、程序中不能使用字体等等一系列问题。

还要在CGDIPlusDemoApp::ExitInstance() 函数(重写)中加入以下代码来关闭GDI +:

GdiplusShutdown(m_gdiplusToken);

上面是所需步骤..

MFC使用GDI+编程基础

封装在GDI+ API中的各种C++类、函数、常量、枚举和结构,都被定义在Gdiplus.h头文件所包含的一系列头文件中。所以,采用MFC进行GDI+编程,必须包含Gdiplus.h头文件。

封装在GDI+类中方法,最后都需要调用GDI+平面API中的相关底层函数,才能完成实际的操作。所以,为了运行GDI+应用程序,在操作系统平台中,必须安装动态链接库。

该动态链接库所对应的静态库文件为,而且它不是C++和MFC的缺省链接库。所以,必须在项目设置,添加该库作为链接器输入的附加依赖项。

因为在Gdiplus.h头文件中,将所有的GDI+的类、函数、常量、枚举和结构等都定义在了命名空间Gdiplus中。所以,一般在GDI+程序中,都必须使用如下的命名空间声明:

using namespace Gdiplus;

例如:

#include

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 // 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 // pop structure packing back to previous state

#endif // !_GDIPLUS_HPP

2)GDI+的初始化与清除

为了在MFC应用程序中使用采用C++封装的GDI+ API,必须在MFC项目的应用程序类中,调用GDI+命名空间中的GDI+启动函数GdiplusStartup和GDI+关闭函数GdiplusShutdown,来对GDI+进行初始化(装入动态链接库,或锁定标志+1)和清除(卸载动态链接库,或锁定标志-1)工作。它们一般分别在应用程序类的InitInstance和ExitInstance重载成员函数中调用。

函数GdiplusStartup和GdiplusShutdown,都被定义在GdiplusInit.h头文件中:

Status WINAPI GdiplusStartup(

OUT ULONG_PTR *token,

const GdiplusStartupInput *input,

OUT GdiplusStartupOutput *output);

void GdiplusShutdown(ULONG_PTR token);

其中:

l 类型ULONG_PTR,是用无符号长整数表示的指针,被定义在basetsd.h头文件中:

typedef _W64 unsigned long ULONG_PTR;

输出参数token(权标),供关闭GDI+的函数使用,所以必须设置为应用程序类的成员变量(或全局变量,不提倡)。

l 结构GdiplusStartupInput和GdiplusStartupOutput,也都被定义在GdiplusInit.h头文件中:

struct GdiplusStartupInput {

UINT32 GdiplusVersion; // Must be 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;

};

n GDI+启动输入结构指针参数input,一般取缺省构造值即可,即(设:无调试事件回调过程、不抑制背景线程、不抑制外部编解码):

input = GdiplusStartupInput(NULL, FALSE, FALSE);

n GDI+启动输出结构指针参数output,一般不需要,取为NULL即可。

注意,采用MFC进行GDI+ API编程时,在使用任何GDI+的功能调用之前,必须先调用GDI+启动函数GdiplusStartup来进行初始化GDI+的工作;在完成所有的GDI+功能调用之后,必须调用GDI+关闭函数GdiplusShutdown来进行清除GDI+的工作。

例如:(创建一个名为GdipDraw的MFC单文档应用程序项目,在项目属性中添加库作为链接器输入的附加依赖项)

// GdipDraw.h

……

class CGdipDrawApp : public CWinApp

{

public:

CGdipDrawApp();

ULONG_PTR m_gdiplusToken;

……

};

//

……

#include

using namespace Gdiplus;

……

BOOL CGdipDrawApp::InitInstance()

{

// 如果一个运行在 Windows XP 上的应用程序清单指定要

// 使用 版本 6 或更高版本来启用可视化方式,

//则需要 InitCommonControlsEx()。否则,将无法创建窗口。

INITCOMMONCONTROLSEX InitCtrls;

= sizeof(InitCtrls);

// 将它设置为包括所有要在应用程序中使用的

// 公共控件类。

= ICC_WIN95_CLASSES;

InitCommonControlsEx(&InitCtrls);

/*注意:下面这两个语句必须加在CWinApp:: InitInstance ();语句之前,不然以后会造成视图窗口不能自动重画、程序中不能使用字体等等一系列问题。*/

GdiplusStartupInput gdiplusStartupInput;

GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);

CWinApp::InitInstance();

……

}

……

int CGdipDrawApp::ExitInstance() // 该函数是自己利用属性窗口,添加的重写函数

{

// TODO: 在此添加专用代码和/或调用基类

GdiplusShutdown(m_gdiplusToken);

return CWinApp::ExitInstance();

}

3)几何辅助类

在GDI+ API中,定义了许多绘图的辅助类,常用的有点、大小和矩形等几何类。它们都是没有基类的独立类,被定义在头文件GdiplusTypes.h中。下面逐个进行介绍:

(1)Point[F](点)

GDI+中,有两种类型的点:整数点(对应于Point类)和浮点数点(对应于PointF类)。下面分别加以介绍:

l 整数点类Point:

class Point {

public:

Point() {X = Y = 0;}

Point(const Point &point) {X = point.X; Y = point.Y;}

Point(const Size &size) {X = ; Y = ;}

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

l 浮点数点类PointF:

class PointF {

public:

PointF() {X = Y = 0.0f;}

PointF(const PointF &point) {X = point.X; Y = point.Y;}

PointF(const SizeF &size) {X = ; Y = ;}

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[F](大小)

GDI+中,也有两种类型的大小(尺寸):整数大小(对应于Size类)和浮点数大小(对应于SizeF类)。下面分别加以介绍:

l 整数大小类Size:

class Size {

public:

Size() {Width = Height = 0;}

Size(const Size& size) {Width = ; Height = ;}

Size(INT width, INT height) {Width = width; Height = height;}

Size operator+(const Size& sz) const {

return Size(Width + , Height + );

}

Size operator-(const Size& sz) const {

return Size(Width - , Height - );

}

BOOL Equals(const Size& sz) const {

return (Width == ) && (Height == );

}

BOOL Empty() const {return (Width == 0 && Height == 0);}

public:

INT Width; // 不是cx和cy

INT Height;

};

注意,这里的大小与GDI的区别:

SIZE和CSize:{cx; cy;} // 不是宽和高

l 浮点数大小类SizeF:

class SizeF {

public:

SizeF() {Width = Height = 0.0f;}

SizeF(const SizeF& size) {Width = ; Height = ;}

SizeF(REAL width, REAL height) {Width = width; Height = height;}

SizeF operator+(const SizeF& sz) const {

return SizeF(Width + , Height + );

}

SizeF operator-(const SizeF& sz) const {

return SizeF(Width - , Height - );

}

BOOL Equals(const SizeF& sz) const {

return (Width == ) && (Height == );

}

BOOL Empty() const {return (Width == 0.0f && Height == 0.0f);}

public:

REAL Width;

REAL Height;

};

(3)Rect[F](矩形)

GDI+中,也有两种类型的矩形:整数矩形(对应于Rect类)和浮点数矩形(对应于RectF类)。下面分别加以介绍:

l 整数矩形类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)。

l 浮点数矩形类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封装中,也有点、大小和矩形的

n 结构:(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;

n 类:(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则没有对应的浮点数版类(但却有结构)。