GDI+编程小结(二)_gdi编程小结二

2020-02-27 其他工作总结 下载本文

GDI+编程小结(二)由刀豆文库小编整理,希望给你工作、学习、生活带来方便,猜你可能喜欢“gdi编程小结二”。

http://www.daodoc.com/

二、GDI+编程

本部分简单介绍GDI+编程中的一些概念与技巧,具体的编程细节请参考《精通GDI+编程》、陈宝楷《GDI+编程》等书籍。

1、Point、浮点数点类PointF;Size、浮点数大小类SizeF;Rect、浮点数矩形类RectF等。

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

2、Color:在GDI+中,色彩是通过Color(色彩)类来描述的。Color类的构造函数分别为: Color();Color(BYTE a,BYTE r,BYTE g,BYTE b);Color(ARGB argb);Color(BYTE r,BYTE g,BYTE b);参数:

a:色彩的透明度(0~255)r、g、b:红、绿、蓝3种色彩分量值(0~255)不同于GDI,GDI+在对色彩支持方面主要体现在对色彩的透明度支持。从本质上讲,透明度是像素之间的一种合成运算。它的计算公式是:

输出色彩=前景色*Alpha/255 + 背景色*(255-Alpha)/2553、Graphics(图形)

图形类Graphics是GDI+的核心,它提供绘制图形、图像和文本的各种方法(操作/函数)(似GDI中的CDC类),还可以存储显示设备和被画项目的属性(到图元文件)。Graphics类及其成员函数都被定义在头文件Gdiplusgraphics.h中。Graphics类的构造函数有如下4种: Graphics(Image* image);// 用于绘制图像 Graphics(HDC hdc);// 用于在当前窗口中绘图

Graphics(HDC hdc, HANDLE hdevice);// 用于在指定设备上绘制图形

Graphics(HWND hwnd, BOOL icm = FALSE);// 用于在指定窗口中绘图可以进行颜色调整 其中,最常用的是第二种——在当前视图窗口中绘图的图形类构造函数。

注意,该构造函数的输入参数,是设备上下文的句柄,而不是CDC类对象的指针。一般可以由CDC对象得到(CDC类含有公用数据成员HDC m_hDC;)6种绘制直线和折线的函数:(前三个为整数版,后三个为对应的浮点数版)// 画折线DrawLines Status DrawLine(const Pen* pen, INT x1, INT y1, INT x2, INT y2);Status DrawLine(const Pen* pen, const Point& pt1, const Point& pt2);Status DrawLines(const Pen* pen, const Point* points, INT count);// 画折线 Status DrawLine(const Pen* pen, REAL x1, REAL y1, REAL x2, REAL y2);Status DrawLine(const Pen* pen, const PointF& pt1, const PointF& pt2);Status DrawLines(const Pen* pen, const PointF* points, INT count);6种绘制矩形和矩形组的函数:(也是前三个为整数版,后三个为对应的浮点数版)// Rectangle = rect angle

http://www.daodoc.com/

Status DrawRectangle(const Pen* pen, const Rect& rect);Status DrawRectangle(const Pen* pen, INT x, INT y, INT width, INT height);Status DrawRectangles(const Pen* pen, const Rect* rects, INT count);Status DrawRectangle(const Pen* pen, const RectF& rect);Status DrawRectangle(const Pen* pen, REAL x, REAL y, REAL width, REAL height);Status DrawRectangles(const Pen* pen, const RectF* rects, INT count);绘制椭圆的函数,如果输入参数所确定的外接矩形的宽高相等,则画圆。(也是前两个为整数版,后两个为对应的浮点数版)

Status DrawEllipse(const Pen* pen, const Rect& rect);Status DrawEllipse(const Pen* pen, INT x, INT y, INT width, INT height)Status DrawEllipse(const Pen* pen, const RectF& rect);Status DrawEllipse(const Pen* pen, REAL x, REAL y, REAL width, REAL height);绘制椭圆弧的函数,如果输入参数所确定的外接矩形的宽高相等,则画圆弧。(也是前两个为整数版,后两个为对应的浮点数版)

Status DrawArc(const Pen* pen, INT x, INT y, INT width, INT height, REAL startAngle, REAL sweepAngle);// sweep 掠过

Status DrawArc(const Pen* pen, const Rect& rect, REAL startAngle, REAL sweepAngle);Status DrawArc(const Pen* pen, REAL x, REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle);Status DrawArc(const Pen* pen, const RectF& rect, REAL startAngle, REAL sweepAngle);

画弧函数的输入参数 // 注意:顺时钟方向 该函数的功能与GDI的Arc相同:

BOOL Arc(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4);BOOL Arc(LPCRECT lpRect, POINT ptStart, POINT ptEnd);但是也有区别,主要是,最后的参数不再是弧的终角,而是弧段所对应的扫描角。这倒是与另一个GDI画圆弧函数类似(其中(x, y)为圆心、nRadius为半径、fStartAngle为起始角、fSweepAngle也为弧段跨角):

BOOL AngleArc(int x, int y, int nRadius, float fStartAngle, float fSweepAngle);当然,GDI+确定矩形的后两个参数也不再是右下角坐标,而改成宽高了,这已经是老问题了。另外要注意的是,角度的单位是度(不是弧度,C++的三角函数采用的是弧度单位),而且都必须是实数。零度角为x轴方向,顺时针方向为正(这与数学上反时针方向为正刚好相反)。// 如上图所示。

绘制多边形的函数,第一个为整数版,后一个为对应的浮点数版: Status DrawPolygon(const Pen* pen, const Point* points, INT count);Status DrawPolygon(const Pen* pen, const PointF* points, INT count);其中,各参数的含义同画折线函数DrawLines的,只是DrawPolygon函数会将点数组中的起点和终点连接起来,形成一个封闭的多边形区域。该函数的功能与GDI的Polygon相同:

BOOL Polygon(LPPOINT lpPoints, int nCount);

注意:GDI+中没有提供,与GDI函数RoundRect(圆角矩形)和Chord(弓弦),具有类似功

http://www.daodoc.com/

能的绘图函数。可以利用矩形+椭圆和弧+直线等函数自己来实现。在GDI+中画填充图,不需像GDI那样得先将刷子选入DC,而是与GDI+画线状图的函数类似,将刷子作为画填充图函数的第一个输入参数。画填充矩形[组] FillRectangle[s] Status FillRectangle(const Brush* brush, const Rect& rect);Status FillRectangle(const Brush* brush, INT x, INT y, INT width, INT height);Status FillRectangles(const Brush* brush, const Rect* rects, INT count);Status FillRectangle(const Brush* brush, const RectF& rect);Status FillRectangle(const Brush* brush, REAL x, REAL y, REAL width, REAL height);Status FillRectangles(const Brush* brush, const RectF* rects, INT count);用指定刷子Brush,填充rect的内部区域,无边线,填充区域包括矩形的左边界和上边界,但不包括矩形的右边界和下边界。功能与GDI的FillRect类似: void FillRect(LPCRECT lpRect, CBrush* pBrush);但是,GDI中没有同时填充一个矩形数组的函数。不过GDI却有GDI+没有的画填充圆角矩形的函数FillSolidRect。画填充[椭]圆FillEllipse Status FillEllipse(const Brush* brush, const Rect& rect);Status FillEllipse(const Brush* brush, INT x, INT y, INT width, INT height);Status FillEllipse(const Brush* brush, const RectF& rect);Status FillEllipse(const Brush* brush, REAL x, REAL y, REAL width, REAL height);GDI中没有类似函数,但可以用(采用当前刷填充的)Ellipse来代替。画饼图DrawPie // pie馅饼

DrawPie与FillPie Status DrawPie(const Pen* pen, const Rect& rect, REAL startAngle, REAL sweepAngle);Status DrawPie(const Pen* pen, INT x, INT y, INT width, INT height, REAL startAngle, REAL sweepAngle);Status DrawPie(const Pen* pen, const RectF& rect, REAL startAngle, REAL sweepAngle);Status DrawPie(const Pen* pen, REAL x, REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle);与GDI的下列函数类似,但是部分输入参数的含义有所不同:

BOOL Pie(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4);BOOL Pie(LPCRECT lpRect, POINT ptStart, POINT ptEnd);

画填充多边形FillPolygon Status FillPolygon(const Brush* brush, const Point* points, INT count);Status FillPolygon(const Brush* brush, const Point* points, INT count, FillMode fillMode);Status FillPolygon(const Brush* brush, const PointF* points, INT count);Status FillPolygon(const Brush* brush, const PointF* points, INT count, FillMode fillMode);前面讲的各种画线状图或填充图的GDI+函数,虽然在形式上与GDI的有所不同(函数名前加了Draw或Fill、将笔或刷作为第一个输入参数、部分位置输入参数改成了大小参数、并增加了浮点数版),但是在功能上却是相同的。

现在要讲的曲线绘制,则是GDI+新增加的内容。曲线在机械设计、工程建筑和图形动画等领域,都有十分广泛应用。

常用的曲线有Bezier(贝塞尔)曲线和样条(spline)曲线。贝塞尔曲线比较简单,适合于

http://www.daodoc.com/

画控制点少的曲线。当控制点太多时,要不曲线的次数(比点数少1)太高,要不拼接比较困难,而且没有局部性(即修改一点影响全局),性能不太好。而样条曲线则可以画任意多个控制点的曲线,曲线的次数也可以指定(一般为二次或三次,如TrueType字体采用的是二次B样条曲线),并且具有局部性。贝塞尔曲线特别是样条曲线有很多变种。常见的贝塞尔曲线有普通贝塞尔曲线和有理贝塞尔曲线。常用的样条曲线有:B样条、β样条、Hermite(厄密)样条、基数样条、Kochanek-Bartels样条和Catmull-Rom样条等。

GDI+中所实现的是普通贝塞尔曲线(不过控制点,位于控制多边形的凸包之内)和基数样条曲线(过控制点)。

基数样条曲线(cardinal spline curve)

// DrawCurve与DrawClosedCurve Status DrawCurve(const Pen* pen, const Point* points, INT count);// tension = 0.5f Status DrawCurve(const Pen* pen, const Point* points, INT count, REAL tension);Status DrawCurve(const Pen* pen, const Point* points, INT count, INT offset, INT numberOfSegments, REAL tension = 0.5f);// 只画部分点

Status DrawCurve(const Pen* pen, const PointF* points, INT count);Status DrawCurve(const Pen* pen, const PointF* points, INT count, REAL tension);Status DrawCurve(const Pen* pen, const PointF* points, INT count, INT offset, INT numberOfSegments, REAL tension = 0.5f);Status DrawClosedCurve(const Pen* pen, const Point* points, INT count);Status DrawClosedCurve(const Pen *pen, const Point* points, INT count, REAL tension);Status DrawClosedCurve(const Pen* pen, const PointF* points, INT count);Status DrawClosedCurve(const Pen *pen, const PointF* points, INT count, REAL tension);其中:

参数tension(张力)指定曲线的弯曲程度,tension = 0.0(直线)~ 1.0(最弯曲)无张力版的函数的 tension = 0.5(缺省值)第3/6个DrawCurve,只画从points[offset]开始的numberOfSegments个点组成的部分曲线段 DrawClosedCurve函数(连接首尾点)画封闭的基数样条曲线 贝塞尔曲线(Bezier curve)DrawBezier Status DrawBezier(const Pen* pen, INT x1, INT y1, INT x2, INT y2, INT x3, INT y3, INT x4, INT y4);Status DrawBezier(const Pen* pen, const Point& pt1, const Point& pt2, const Point& pt3, const Point& pt4);Status DrawBeziers(const Pen* pen, const Point* points, INT count);Status DrawBezier(const Pen* pen, REAL x1, REAL y1, REAL x2, REAL y2, REAL x3, REAL y3, REAL x4, REAL y4);Status DrawBezier(const Pen* pen, const PointF& pt1, const PointF& pt2, const PointF& pt3, const PointF& pt4);Status DrawBeziers(const Pen* pen, const PointF* points, INT count);填充封闭基数样条曲线

FillClosedCurve Status FillClosedCurve(const Brush* brush, const Point* points, INT count);Status FillClosedCurve(const Brush* brush, const Point* points, INT count, FillMode fillMode, REAL tension = 0.5f);Status FillClosedCurve(const Brush* brush, const PointF* points, INT count);Status FillClosedCurve(const Brush* brush, const PointF* points, INT count, FillMode fillMode, REAL tension = 0.5f);

http://www.daodoc.com/

GDI中没有用于清屏的专门函数,得自己用背景色画窗口大小的填充矩形,或者调用窗口类的Invalidate和UpdateWindow函数。现在,GDI+有了清屏函数Clear: Status Clear(const Color &color);其中的输入参数color,为用户指定的填充背景色。例如:

Graphics graph(GetDC()->m_hDC);

graph.Clear(Color::White);// 使用Graphics类之对象调用

4、Pen 与GDI中的一样,GDI+中的笔(pen钢笔/画笔)也是画线状图的工具,但是功能更加强大。例如:透明笔、图案笔、自定义虚线风格、线帽、笔的缩放和旋转、笔的连接点属性等。GDI+中的笔对应于Pen类,被定义在GdiplusPen.h头文件中。笔的构造函数主要有两个:

Pen(const Color &color, REAL width = 1.0);// 单色笔

Pen(const Brush *brush, REAL width = 1.0);// 纹理图案笔

其中,最常用的是第一个,它构造一个颜色为color,宽度为width(缺省为1)的单色笔。如果颜色的α值

5、Brush 与GDI中的一样,GDI+中的刷(brush画刷/画笔)也是画填充图的工具,GDI+中也有与GDI相对应的实心刷(单色刷)、条纹刷(影线刷)和纹理刷(图像刷)。不过,GDI+又新增加了功能强大的线性渐变刷和路径渐变刷,而且还为所有这些刷各自建立了对应的类,基类是Brush(功能少)。

GDI+刷类的层次结构 //(1)SolidBrush实心刷 //(2)HatchBrush 条纹刷 //(3)TextureBrush 纹理刷

//(4)LinearGradientBrush 线性渐变刷

// gradient倾斜的,梯度 //(5)PathGradientBrush 路径渐变刷

所有刷类都被定义在头文件GdiplusBrush.h中。

6、文字

GDI+的文本排版和字体处理的功能比GDI的更加强大。特别是Windows XP提供了对LCD(液晶)显示器的特殊优化功能,GDI+也提供了对应的ClearType(清晰活字)文字处理技术,以增强字体的清晰度。另外,GDI+还提供了构造专用字体集的功能,可以包含私有的临时字体(不需预先安装到系统中)。Windows中使用的字体,一般是TrueType(真实活字)字体(TTF = TrueType Font),它是1991年Apple 和Microsoft 联合开发的一种字体技术,采用二次B样条曲线来描述字符的轮廓。在GDI+中,与文字相关的类有:字体族类FontFamily、字体类Font和字体集类FontCollection及其两个派生类InstalledFontCollection(已安装字体集)和PrivateFontCollection(专用字体集)。(在GDI中只有CFont一个字体类)这些类的层次结构为:

在GDI中,我们用CDC类的成员函数TextOut、DrawText和ExtTextOut等来输出文本串。在GDI+中,我们则是利用Graphics类的重载成员函数DrawString来绘制文本。

http://www.daodoc.com/

7、路径

路径(path)是一系列相互连接的直线和曲线,由许多不同类型的点所构成,用于表示复杂的不规则图形,也叫做图形路径(graphics path)。路径可以被画轮廓和填充,也可以用于创建区域和路径渐变刷等。

在GDI中也有路径(我们没有讲),但是它只是作为DC的一种状态才能存在。独立的路径对象,则是GDI+的新特点。

8、区域

区域(region)由若干几何形状所构成的一种封闭图形,主要用于复杂图形的绘制、图形输出的剪裁和鼠标击中的测试。最简单也是最常用的区域是矩形,其次是椭圆和多边形以及它们的组合。这些也正是GDI所支持的区域类型。

GDI+中的区域是一种显示表面的范围(an area of the display surface),可以是任意形状(的图形的组合),边界一般为路径。除了上面所讲的矩形、椭圆、多边形之外,其边界还可以含直线、折线、弧、贝塞尔曲线和样条曲线等开图形,其内容还可以包含饼、闭曲线等闭图形。

在GDI+中,区域所对应的类是Region,它是一个独立的类(没有基类,也没有派生类)。但是它又若干相关的类,如各种图形类和图形路径类等。Region类有6个构造函数:

Region(VOID);// 创建一个空区域

Region(const Rect &rect);// 创建一个整数型矩形区域 Region(const RectF &rect);// 创建一个浮点数型矩形区域 Region(const GraphicsPath *path);// 由图形路径来创建区域

Region(const BYTE *regionData, INT size);// 由(另一)区域的数据构造区域 Region(HRGN hRgn);// 由GDI的区域句柄构造区域

其中,创建矩形区域最简单,由路径创建区域最常用。

9、变换

变换(transform)是GDI+新增加的强大功能,包括图形对象的简单变换和基于矩阵的坐标变换、图形变换、图像变换、色彩变换、路径变换和区域变换等。

GDI+的核心——图形类Graphics,提供了3个成员函数,可以对其所绘制的图形进行平移(translate)、旋转(rotate)和伸缩(scale比例尺/缩放)等基本的图形变换:(与纹理刷类中的对应函数的原型是一样的)

Status TranslateTransform(REAL dx, REAL dy, MatrixOrder order = MatrixOrderPrepend);Status RotateTransform(REAL angle, MatrixOrder order = MatrixOrderPrepend);Status ScaleTransform(REAL sx, REAL sy, MatrixOrder order = MatrixOrderPrepend);其中的最后一个输入参数为矩阵相乘的顺序,取值为矩阵顺序枚举类型MatrixOrder中的符号常量,缺省值都为MatrixOrderAppend(左乘): typedef enum {

MatrixOrderPrepend = 0, // 矩阵左乘(预先序,前置)

MatrixOrderAppend = 1 // 矩阵右乘(追加序,后缀)} MatrixOrder;因为这些变换都可以用矩阵表示,而且与图形对象已经设置的现有变换矩阵要进行合成(相当于两个变换矩阵进行乘法运算)。在图形对象的这三种基本变换中,最常用的是第一种——平移变换。我们在前面曾多次使用,避免了重复定义(有坐标平移的)绘图区域的麻烦。

http://www.daodoc.com/

10、图像

GDI+支持如下9种用于Windows的常见图像格式:

——BitMaP(位图),扩展名为.BMP,由Microsoft与IBM于1980年代中期为Windows和PS/2制订的图像格式,一般不压缩。支持黑白、伪彩图、灰度图和真彩图,每像素位数可为1、4、8、16、24、32、64等,常用的是24位位图。

——Graphics Interchange Format(可交换图形格式),扩展名为.GIF,由CompuServe公司1987年制定,采用无损的变长LZW压缩算法。只支持伪彩图(最多256索引色),宽高用双字节无符号整数表示(最多64K*64K像素)。可存储多幅图片,常用于简单的网络动画。压缩比较高,使用广泛。

——Joint Photographic Experts Group(联合图象专家组),扩展名为.JPG,是国际标准化组织ISO和IEC于1991年联合制定的静态图像压缩标准,采用以DCT为主的有损压缩方法。支持灰度图和真彩图,但是不支持伪彩图。压缩比高,使用广泛。

——EXchangeable Image File Format(可交换图像文件格式),扩展名为.Exit?,由JEIDA(Japan Electronic Industry Development Aociation日本电子工业发展协会/日本电子情报技术产业协会)于1996年10月制定。用于数码相机,内含JPEG图像,另包含拍摄日期、快门速度、曝光时间、照相机制造厂商和型号等相关信息。

——Portable Network Graphic Format(可移植网络图形格式,读成“ping”),扩展名为.png,由W3C(World Wide Web Consortium万维网协会)于1996年10月推出的一种标准图像格式,2003年成为ISO国际标准。PNG采用与GIF一样的无损压缩方法,但是除了伪彩图外,PNG还支持多达16位深度的灰度图像和48位深度的彩色图像,并且还可支持多达16位的α通道数据。

——Tag Image File Format(标签图像文件格式),扩展名为.tif,由Aldus于1986年秋联合多家扫描仪制造商和软件公司共同开发,支持黑白、索引色、灰度、真彩图,可校正颜色和调色温,支持多种压缩编码(如Huffman、LZW、RLE),可存储多幅图片。常用于对质量要求高的专业图像的存储。

——icon(图标),扩展名为.ico,由Microsoft与IBM于1980年代中期为Windows和PS/2制订的图标图像格式。图像大小为16*

16、32*32或54*64。

——Windows MetaFile(视窗元文件),扩展名为.WMF,由Microsoft与IBM于1980年代中期为Windows和PS/2制订的图形文件格式,用于保存GDI的绘图指令记录。

——Enhanced Windows MetaFile(增强型视窗元文件),扩展名为.EMF,是微软公司于1993年随32位操作系统Windws NT推出的一种改进的WMF格式,用于Win32。GDI+使用的是扩展EMF格式——EMF+。

GDI+的图像及其处理的功能十分强大,可以用不同的格式加载、保存和操作图像。但由于篇幅所限,本小节只介绍最基本的内容。GDI+中有三个图像类,其中的Image(图像)为基类,其他两个为它的派生类——Bitmap(位图)和Metafile([图]元文件/矢量图形)。它们的类层次结构如下图所示:

图像类的层次结构

除此之外,还有大量与图像处理有关的GDI+类,如Effect类及其11个派生类以及与图像数据和信息有关的7个独立类。由于时间关系,我们只准备介绍上面这三个主要的图像类及其基本操作。

http://www.daodoc.com/

11、图元文件 从一开始GDI就支持(图)元文件(metafile),早期(1985年)的版本为WMF(Windows MetaFile视窗元文件),主要针对Win16(Win3.x),后来(1990年)也支持Win32(Win95/ 98/Me)。以后(1993年)随Windows NT推出了改进的元文件版本——EMF(Enhanced Windows MetaFile增强型视窗元文件),只支持Win32(Win95/98/Me/NT/2000/XP)。现在(2001年)又随GDI+推出了加强型EMF——EMF+,可以同时支持GDI和GDI+。元文件所支持的GDI类型

元文件类型 Win16 GDI Win32 GDI Win32/64 GDI+ WMF √ √ × EMF × √ × EMF+ × √ √

虽然在GDI+中,将图元文件所对应的类Metafile作为Image的派生类,但这只是为了图元文件可以同时处理图形和图像。其实图元文件中所包含的就是一系列绘图(包括绘制图像)指令及参数,属于矢量图形文件。它所占空间小、可以任意缩放(不会产生马赛克效应),但是绘制图形需要一定的时间。

在GDI+中,图元文件对应的类为Metafile,它是Image类的派生类。GDI+的Metafile类支持三种类型的图元文件:仅EMF类型、仅EMF+类型、EMF及EMF+双重类型(缺省值)。它们对应于枚举类型: typedef enum { EmfTypeEmfOnly = MetafileTypeEmf, // 仅EMF类型

EmfTypeEmfPlusOnly = MetafileTypeEmfPlusOnly, // 仅EMF+类型

EmfTypeEmfPlusDual = MetafileTypeEmfPlusDual // EMF及EMF+双重类型 } EmfType;// enhance meta file Metafile类有13个构造函数: // 文件型

Metafile(const WCHAR *filename);Metafile(const WCHAR *fileName, HDC referenceHdc, EmfType type = EmfTypeEmfPlusDual, const WCHAR *description = NULL);Metafile(const WCHAR *fileName, HDC referenceHdc, const Rect &frameRect, MetaFileFrameUnit frameUnit = MetafileFrameUnitGdi, EmfType type = EmfTypeEmfPlusDual, const WCHAR *description = NULL);Metafile(const WCHAR *fileName, HDC referenceHdc, const RectF &frameRect, MetafileFrameUnit frameUnit = MetafileFrameUnitGdi, EmfType type = EmfTypeEmfPlusDual, const WCHAR *description = NULL);// 流型

Metafile(IStream *stream);Metafile(IStream *stream, HDC referenceHdc, EmfType type = EmfTypeEmfPlusDual, const WCHAR *description = NULL);Metafile(IStream *stream, HDC referenceHdc, const Rect &frameRect, MetafileFrameUnit frameUnit = MetafileFrameUnitGdi, EmfType type = EmfTypeEmfPlusDual, const WCHAR *description = NULL);Metafile(IStream *stream, HDC referenceHdc, const RectF &frameRect, MetafileFrameUnit

http://www.daodoc.com/

frameUnit = MetafileFrameUnitGdi, EmfType type = EmfTypeEmfPlusDual, const WCHAR *description = NULL);// DC句柄型

Metafile(HDC referenceHdc, EmfType type = EmfTypeEmfPlusDual, const WCHAR *description = NULL);Metafile(HDC referenceHdc, const Rect &frameRect, MetafileFrameUnit frameUnit = MetafileFrameUnitGdi, EmfType type = EmfTypeEmfPlusDual, const WCHAR *description = NULL);Metafile(HDC referenceHdc, const RectF &frameRect, MetaFileFrameUnit frameUnit = MetafileFrameUnitGdi, EmfType type = EmfTypeEmfPlusDual, const WCHAR *description = NULL);// WMF/EMF句柄型

Metafile(HENHMETAFILE hEmf, BOOL deleteEmf = FALSE);Metafile(HMETAFILE hWmf, const WmfPlaceableFileHeader *wmfPlaceableFileHeader, BOOL deleteWmf = FALSE);其中用到的枚举类型有: typedef enum {

MetafileFrameUnitPixel = UnitPixel, // 象素

MetafileFrameUnitPoint = UnitPoint, // 点

MetafileFrameUnitInch = UnitInch, // 英寸

MetafileFrameUnitDocument = UnitDocument, // 文挡

MetafileFrameUnitMillimeter = UnitDocument + 1, // 毫米

MetafileFrameUnitGdi = UnitDocument + 2 // GDI+单位数目 } MetafileFrameUnit;typedef struct {

UINT32 Key;// 键

INT16 Hmf;//

PWMFRect16 BoundingBox;// 边界盒

INT16 Inch;// 英寸

UINT32 Reserved;// 保留

INT16 Checksum;// 检测和 } WmfPlaceableFileHeader;http://www.daodoc.com/

Metafile(HDC referenceHdc, EmfType type = EmfTypeEmfPlusDual, const WCHAR *description = NULL);它用于构造内存元文件。这些内存元文件构造函数还有对应的流构造函数版本。Metafile类的其他成员函数有:

// 显示元文件记录,需要与Graphics类的EnumerateMetafile Status PlayRecord(EmfPlusRecordType recordType, UINT flags, UINT dataSize, const BYTE *data);// 函数及用户自定义的回调函数配套使用(似GDI的)

static UINT EmfToWmfBits(HENHMETAFILE hemf, UINT cbData16, LPBYTE pData16, INT iMapMode, EmfToWmfBitsFlags eFlags);// 用于EMF到WMF的转换 HENHMETAFILEGetHENHMETAFILE(VOID);// 可用于EMF的SDK函数 // 获取和设置底层光栅限制,用于减少刷空间大小

// 陈宝楷??? UINT GetDownLevelRasterizationLimit(VOID);Status SetDownLevelRasterizationLimit(UINT metafileRasterizationLimitDpi);// 获取元文件头

Status GetMetafileHeader(MetafileHeader *header)const;static Status GetMetafileHeader(const WCHAR *filename, MetafileHeader *header);static Status GetMetafileHeader(IStream *stream, MetafileHeader *header);static Status GetMetafileHeader(HENHMETAFILE *hEmf, MetafileHeader *header);static Status GetMetafileHeader(HMETAFILE hWmf, const WmfPlaceableFileHeader *wmfPlaceableFileHeader, MetafileHeader *header);为了将绘图记录保存到图元文件中,需要先创建元文件对象,然后用该图元文件对象再来创建图形对象,最后调用图形类的各种绘图函数来向图元文件中添加绘图记录。具体方法如下:

可以先使用Metafile类的用于创建新图元文件的构造函数(带DC参数的),如 Metafile(const WCHAR *fileName, HDCreferenceHdc, EmfType type = EmfTypeEmfPlusDual, const WCHAR *description = NULL);来创建元文件对象。

然后使用Graphics类的构造函数(注意,Metafile是Image的派生类)Graphics(Image* image);来创建图形对象。

最后调用各种图形类的图形设置、操作和绘制函数成员函数来向图元文件添加绘图记录。例如:

Metafile *myMetafile = newMetafile(L“MyDiskFile.emf”, GetDC()->m_hDC);

Graphics *myGraphics = new Graphics(myMetafile);

// SmoothingMode::tiAlias不能在VC中使用,可在C#中使用。myGraphics->SetSmoothingMode(SmoothingModeAntiAlias);

myGraphics->RotateTransform(30);

// Create an elliptical clipping region.GraphicsPath myPath;

myPath.AddEllipse(0, 0, 200, 100);

Region myRegion(&myPath);

myGraphics->SetClip(&myRegion);

Pen myPen(Color(255, 0, 0, 255));

http://www.daodoc.com/

myGraphics->DrawPath(&myPen, &myPath);

for(int j=0;jDrawLine(&myPen,0,0,300-j,j);

delete myGraphics;deletemyMetafile;可以先使用Metafile类的用于打开已有图元文件的构造函数(不带DC参数的),如 Metafile(const WCHAR *filename);来创建元文件对象。

然后再调用Graphics类的各种DrawImage成员函数,如: Status DrawImage(Image *image, INT x, INT y);来重画图元文件中的所有绘图记录。

另外,为了获取当前图元文件的边界矩形,可以先调用Metafile类的成员函数: Status GetMetafileHeader(MetafileHeader *header)const;来获取MetafileHeader对象,然后再用MetafileHeader类的成员函数: void GetBounds(Rect *rect);得到边界矩形。可用于Graphics类的DrawImage成员函数: DrawImage(Image *image, const Rect &rect);

注意,如果用带DC参数的构造函数来创建Metafile对象,则会清空原图元文件(以便重新开始添加记录),不能用于图元文件的播放。可以利用Metafile类的成员函数

Status PlayRecord(EmfPlusRecordType recordType, UINT flags, UINT dataSize, const BYTE *data);来重画图元文件中指定记录。与EMF中讨论的类似,该函数需要与Graphics类的枚举元文件成员函数(共有12个同名的重载函数),如: StatusEnumerateMetafile(const Metafile *metafile, const PointF &destPoint, EnumerateMetafileProccallback, VOID *callbackData = NULL, ImageAttributes *imageAttributes = NULL);配套使用,该函数遍历图元文件的每个记录,并调用用户自定义的回调函数(该函数可以自己命名)

BOOL CALLBACK metaCallback(EmfPlusRecordType recordType, unsigned int flags, unsigned int dataSize, const unsigned char* pStr, void* callbackData);对记录进行各种处理,包括使用元文件的成员函数PlayRecord来绘制(播放)记录。在GDI+中,想实现交互绘图时的窗口动态重画,非常困难。虽然Metafile类有一个成员函数

HENHMETAFILE GetHENHMETAFILE(VOID);可以用于获取图元文件的句柄,但经过我的实验发现,它只对使用不带DC输入参数的构造函数所创建的不能用于添加绘图记录的Metafile对象有效。

另外,虽说可以创建内存Metafile对象,但是GDI+却没有提供任何办法(没有复制、保存、克隆等函数,父类Image的对应函数对写入型Metafile对象都是无效的),可将其保存到图元文件中。因为无法获得用于添加记录的图元文件的句柄,所以各种SDK函数也派不上用场。

因为除了帮助文档,几乎无资料可看,唯一的途径就是编码做试验。下面是我经过很长时间,http://www.daodoc.com/

好不容易才摸索出来的,一种可行的解决办法(但是很臭。你们可以寻找其他办法,如果有了更好的方法,请与大家共享):

(说明:为了防止重画图元文件时,图形的位置有偏移或其大小发生变化,可以采用如下的构造函数:

Metafile(const WCHAR *fileName, HDC referenceHdc, const Rect &frameRect, MetaFileFrameUnit frameUnit = MetafileFrameUnitGdi, EmfType type = EmfTypeEmfPlusDual, const WCHAR *description = NULL);来创建Metafile对象。其中的边框矩形,可以设置为屏幕大小,并使用像素单位。该边框同时还用于进行图元文件重画的Graphics类的DrawImage函数。)

在视图类中定义如下几个类变量:Metafile对象及其对应的Graphics对象的指针、边框矩形、两个图元文件名的宽字符串数组(以便绕开GDI+的文件锁定功能)、以及在这两个文件名中切换的整数。如:

Metafile *mf;

Graphics *mfGraph;

Rect rect0;wchar_t *fns[2];

// wchar_t

int fni;

在视图类的构造函数中,初始化部分类变量:

mf = NULL;

mfGraph = NULL;

fns[0] = L“draw.emf”;

fns[1] = L“draw0.emf”;

fni = 0;

在视图类的初始化函数OnInitialUpdate中,计算边框矩形、创建Metafile对象:

HDC hdcRef = GetDC()->m_hDC;

rect0.X = 0;

rect0.Y = 0;

rect0.Width = GetDeviceCaps(hdcRef, HORZRES);

rect0.Height = GetDeviceCaps(hdcRef, VERTRES);

mf = new Metafile(fns[fni], hdcRef, rect0, MetafileFrameUnitPixel);

mfGraph = new Graphics(mf);

在视图类的OnLButtonUp等函数中,利用图元文件所对应的图形对象,向图元文件添加各种绘图记录。如:

mfGraph->DrawLine(&Pen(Color::Green), p0.x, p0.y, point.x , point.y);

……

在视图类的OnDraw函数中,删除当前元文件对象(系统才会将元文件的内容写入磁盘)和对应的图形对象,打开该磁盘元文件并播放。然后,切换文件名,创建新的元文件对象和对

http://www.daodoc.com/

应的图形对象,并将老元文件中现有的记录,通过新元文件所对应的图形对象的图像绘制,加入到新元文件中,最后删除老元文件的句柄。如:

delete mfGraph;

delete mf;

Metafile *mf0 = new Metafile(fns[fni]);

Graphics graph(pDC->m_hDC);

graph.DrawImage(mf0, rect0);fni =!fni;// 相当于if(fni)fni = 0;else fni = 1;

mf = new Metafile(fns[fni], pDC->m_hDC, rect0, MetafileFrameUnitPixel);

mfGraph = new Graphics(mf);

mfGraph->DrawImage(mf0, rect0);

delete mf0;

最后,在视图类的析构函数中,删除当前元文件对象(系统会将元文件的内容写入磁盘)和对应的图形对象。例如:

delete mfGraph;

delete mf;

编程小结

编程小结(一)一.累加:加数1+加数2+加数3+„„+加数n (n个加数相加) 假设我们用i表示我们的加数数目,例如:当i=9时,就表示加数9 模版:int i,sum=0; (注意:如果是分数或者小数sum就是floa......

编程题小结

1011 字符逆序Description:将一个字符串str的内容颠倒过来,并输出。Str的长度不超过100个字符。Input:输入包括一行。第一行输入的字符串。 Output:输出转换好的逆序字符串。 S......

编程小结3

电脑编程从例1-1中可以看出C语言的一些书写格式和编程风格,下面将做具体解释。1.文件包含命令2.主函数3.变量的定义4.格式输入函数5.格式输出函数6.注释C语言程序编写规则从例1-1中......

编程小结1

编程人与人交流使用人类语言,人与计算机交流使用计算机语言。随着计算机技术的发展,计算机语言也逐步得到完善。C语言是当今世界应用最为广泛的程序设计语言。认识C语言有助于......

数控编程课程设计小结

数控编程课程设计小结我们这次所做的课程设计的零件属于回转体类零件,由圆弧、圆锥面、倒角、内外螺纹、内孔、退刀槽等几部分组成,随着课程设计的做完,也将意味我的大学生活即......

《GDI+编程小结(二).docx》
将本文的Word文档下载,方便收藏和打印
推荐度:
GDI+编程小结(二)
点击下载文档
相关专题 gdi编程小结二 小结 GDI gdi编程小结二 小结 GDI
[其他工作总结]相关推荐
[其他工作总结]热门文章
下载全文