MFC使用GDI+编程基础【收集整理】

来源:互联网 发布:福州美工培训学校 编辑:程序博客网 时间:2024/05/14 22:03

一、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;

 

……

 

1GdiPlus.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

 

2GDI+的初始化与清除

 

为了在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+的工作。

 

例如,创建一个名为GdipDrawMFC单文档应用程序项目,在项目属性中添加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中。下面逐个进行介绍:

 

1Point/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; // 大写XY

    INT Y;

};

 

其中:

typedef int  INT; // 4字节有符号整数(windef.h

 

注意,这里的点与GDI的区别:

POINTCPoint{x; y;} // 小写xy

 

浮点数点类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+新增的功能,这些在各种工程技术领域都非常有用。因为一般的实际图形设计,都是基于实数坐标的。包括机械(机床/汽车/轮船/飞机等)、建筑(房屋/桥梁/道路/堤坝等)和图形动画设计(形状/物体/人物/背景/轨迹等)等设计,都必须使用浮点参数和坐标系。

 

2Size/ 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; // 不是cxcy

    INT Height;

};

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

SIZECSize{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;

};

 

3Rect/ 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; // 不是lefttop

    INT Y;

    INT Width; // 更不是rightbottom

    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;

};

 

GDIMFC封装中,也有点、大小和矩形的

 

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

0 0