第10章Windows图形处理与文本输入输出_第1页
第10章Windows图形处理与文本输入输出_第2页
第10章Windows图形处理与文本输入输出_第3页
第10章Windows图形处理与文本输入输出_第4页
第10章Windows图形处理与文本输入输出_第5页
已阅读5页,还剩101页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、第10章 Windows图形处理与文本输入输出在Windows应用程序中,图形和文本都是使用图形设备接口(Graphics Device Interface,GDI)以图形的方式进行处理的。图形设备接口是一个可执行程序,它接受Windows应用程序的绘图请求,并将它们传给相应的设备驱动程序,完成特定于硬件的输出。学习本章,读者可以掌握Windows中屏幕绘图的基础知识,掌握利用MFC开发图形操作应用程序的步骤和方法。10.1 设 备 环 境在MFC程序设计中,屏幕的绘图是通过设备环境实现的,它是图形设备接口的重要元素。它代表了具体的物理设备,隐藏了物理设备的差异,例如打印机和屏幕之间的差异。设

2、备的无关性使得用户不必关心具体的物理设备的显示,只需要调用相应的函数去进行显示就可以了。10.1.1 设备环境类设备环境(Device Context,DC)包含了要被绘制的设备的信息,例如显示器、打印机等。利用GDI可以方便地处理来自应用程序的图形绘制的函数调用,然后把这些调用传递给合适的设备驱动程序,由设备驱动程序来进行硬件操作,绘制相应的图形并进行显示。在利用GDI进行操作时需要得到设备环境,使得GDI可以明确具体的设备。此外,设备环境中还保存了绘图所需要的数据结构。例如图形的颜色、画笔、字体等。设备环境和GDI,以及应用程序之间的关系如图10.1所示。图10.1 设备环境和GDI在MF

3、C中,利用类CDC封装了设备环境和GDI,它封装了绘图所需要的所有成员函数。它定义了一般物理设备的设备环境。为了可以使用具体的物理环境,CDC派生了几个类,分别是CPaintDC、CClientDC、CWindowDC和CMetaFileDC。下面对这几个类分别进行介绍。1CPaintDC这是一个专门用来显示功能的类,在实际应用中只要得到相关的CDC指针,就可以将它当成任何设备环境的指针使用。2CClientDCCClientDC是表示在窗口的客户区内进行绘图。这个区域不包含标题栏、菜单栏、窗口的边框和状态栏。绘图时客户区的左上角的坐标为(0,0)。CClientDC的构造函数调用GetDC(

4、),析构函数调用ReleaseDC()。3CWindowDCCWindowDC类的设备环境表示整个窗口(包括用户区和非用户区)。它在窗口的任何位置进行绘图。它定义窗口的左上角坐标为(0,0)。CWindowDC的构造函数调用 GetWindowDC(),析构函数调用ReleaseDC()。4CMetaFileDCCMetaFileDC类封装了在Windows图元文件中绘图的方法。图元文件是一系列与设备无关的图片集,一个图元文件包含图形设备接口,可以通过重放命令来创建图形。CMetaFileDC类的使用方法如下所示。(1)定义基于CMetaFileDC类的对象;(2)调用CMetaFileDC:

5、Create()方法初始化该对象;(3)发送CDC GDI命令到该对象;(4)调用CMetaFileDC:Close()关闭元文件;(5)调用CDC:PlayMetaFile()方法回放元文件。由于CMetaFileDC应用场合较少,本章不再进行介绍。10.1.2 映射模式在Windows中提供了多种坐标系,这些坐标系可以通过一定的方法进行转换,也称为坐标系的映射。一种坐标系称为一种映射模式,它定义了设备坐标即物理坐标与逻辑坐标的关系。在程序中可以利用函数SetMapMode()来设置映射模式。下面对常用的映射模式进行介绍。1MM_TEXT这是一种默认坐标形式,它定义在屏幕客户区,x轴向右增长

6、,y轴向下增长。x轴和y轴的坐标单位都是设备的像素点,这种映射模式和设备坐标十分接近,可以很直观地进行坐标变换。MM_TEXT模式定义左上角为坐标原点。在程序中可以利用函数CDC:SetWindowOrg(int x,int y)和函数CDC:SetViewportOrg(int x,int y)来重新定义坐标原点。需要说明的是CDC:SetWindowOrg(int x,int y)将以设备单位定义窗口原点,而CDC:SetViewport Org(int x,int y)将以逻辑单位定义视口原点。因此在定义了CDC:SetWindowOrg(int x,int y)以后,显示图形时需要将坐

7、标减去定义了的横纵坐标才可以使得设备坐标进行正确显示。注意:默认值是采用的MM_TEXT映射模式,这也是一种最常用的映射模式。一般情况下,程序员不必改变这种映射模式。2固定比例的映射模式这种映射模式定义了逻辑单位与设备单位进行转化的方式。这种映射方式可改变视口原点,但不能改变比例因子,因此称为固定比例的映射模式。常见的固定比例映射模式如下所示。MM_LOENGLISH:0.01英寸。MM_HIENGLISH:0.001英寸。MM_LOMETRIC:0.1毫米。MM_HIMETRIC:0.01毫米。MM_TWIPS:1/1440英寸。这些模式定义x轴坐标向右增长,y轴坐标向下递减。这种坐标模式下

8、,Windows可以自动将逻辑单位转换为设备单位,可以保证不同设备下图形的大小保持不变。3可变比例的映射模式Windows中提供了两种可以自定义比例的映射模式。程序员可以修改比例因子和坐标原点。这两种模式如下所示。MM_ISOTROPIC:纵横比为1:1,即保证横纵坐标的比例一致。MM_ANISOTROPIC:可以分别修改x 和 y的比例。在程序中有时需要将逻辑坐标与物理坐标进行转换,下面给出其转换公式:x(y)比例因子= x(y)视口范围/ x(y)窗口范围。设备x(y) =逻辑x(y)* x(y)比例因子+ x(y)坐标原点。上面介绍了几种映射模式,这些映射模式决定了设备坐标和逻辑坐标之间

9、的关系,在应用中应注意不同模式的区别。10.2 绘图在MFC中利用类的形式封装了绘图工具,并且定义了绘图中需要的数据类型。本节介绍常见的绘图工具和绘图相关的数据类型。10.2.1 画笔画笔是用来绘制直线和曲线的工具,在MFC中利用CPen类封装了画笔功能。一个画笔通常具有宽度、线型和颜色3种属性。画笔的宽度表示了绘图中线条的宽度,一般以像素表示。线型是绘图中线条的样式,一般包括虚线、实线、点划线等多个类型。在MFC中线型的样式及其定义如表10.1所示。表10.1 线型的定义及其说明线线 型型 定定 义义说说 明明线线 型型 定定 义义说说 明明PS_DASH虚线PS_INSIDEFRAME实线

10、(内框线)实线(内框线)PS_DASHDOT点划线PS_NULL无无PS_DASHDOTDOT双点划线PS_SOLID实线实线PS_DOT点线点线 在程序中,可以利用CPen的构造函数创建画笔。CPen ( int nPenStyle, int nWidth, COLORREF crColor );CPen ( int nPenStyle, int nWidth, const LOGBRUSH* pLogBrush, int nStyleCount = 0, const DWORD* lpStyle = NULL );或者利用CPen的成员函数CreatePen()来创建画笔。BOOL Cre

11、atePen (int nPenStyle,int nWidth,COLORREF crColor);BOOL CreatePen( int nPenStyle, int nWidth, const LOGBRUSH* pLogBrush, int nStyleCount = 0, const DWORD* lpStyle = NULL );参数nPenStyle、nWidth、crColor分别指定了画笔的线型、宽度和颜色。关于COLORREF这一数据类型,在前面已有所接触,在下面还将详细讲述。在此不再介绍。需要注意的是当创建好画笔以后需要利用CPen* SelectObject( CPen

12、* pPen )将画笔选入设备环境,这时才可以使用此画笔。【示例10.1】 创建一个画笔,并且选入设备环境。CPen *oldpen;/保存旧画笔CPen pen(PS_DOT,1,RGB(0,0,0);/创建新画笔oldpen=pDC-SelectObject(&pen);/选入设备环境/画图操作pDC-SelectObject(&oldpen);/恢复画笔分析:上面的例子首先创建一个新画笔,在选入设备环境时保存旧画笔,然后进行画图操作,在结束时恢复画笔。上面的画笔在退出OnDraw()函数时就会销毁画笔,如果需要保存画笔,则需要保存画笔对象的句柄。【示例10.2】 创建画笔

13、,并保存其句柄。CPen *oldpen;CPen pen(PS_DOT,1,RGB(0,0,0);oldpen=pDC-SelectObject(&pen);/选入设备环境m_oldPen=(HPEN)oldpen-GetSafeHandle();/保留画笔句柄/画图操作pDC-SelectObject(&oldpen);分析:上面的代码段中m_oldPen是一个HPEN变量。如果把它定义为一个类的成员变量,则在其他函数中可以使用下面的语句再次从该句柄中获得画笔。pDC-SelectObject(CPen:FromHandle(m_oldPen);说明:一般使用GDI对象时都

14、应该在使用结束后恢复原来的GDI对象,这样可以保证当前设备环境的GDI对象保持不变。10.2.2 画刷画刷是可以填充某个区域的绘图工具,在MFC中利用CBrush类封装了画刷的功能。画刷通常包含填充颜色、填充图案、填充样式3个属性。可以利用CBrush的构造函数创建画刷。其函数原型有下面3种形式:CBrush( COLORREF crColor );/创建实心画刷CBrush( int nIndex, COLORREF crColor );/创建填充画刷CBrush( CBitmap* pBitmap );/创建利用pBitmap指向的位图作为填充的画刷参数crColor指定了画刷的前景色,n

15、Index指定了画刷的填充样式,它的取值如下所示。HS_BDIAGONAL:从左到右向下45斜线。HS_CROSS:十字线。HS_DIAGCROSS:45交叉线。HS_FDIAGONAL:从左到右向上45斜线。HS_HORIZONTAL:水平线。HS_VERTICAL:垂直线。除了使用构造函数创建画刷外,还可以利用如下方法创建画刷。BOOL CreateSolidBrush( COLORREF crColor ); /创建实心画刷BOOL CreateHatchBrush( int nIndex, COLORREF crColor ); /创建填充画刷BOOL CreatePatternBru

16、sh( CBitmap* pBitmap ); /创建pBitmap指向位图为填充的画刷BOOL CreateDIBPatternBrush( HGLOBAL hPackedDIB, UINT nUsage ); /用指定的DIB创建画刷BOOL CreateSysColorBrush( int nIndex ); /创建系统颜色的画刷画刷的使用与画笔一样,创建好画刷以后需要利用CBrush* SelectObject( CBrush* pBrush );将画刷选入设备环境,这时才可以使用此画刷。【示例10.3】 创建一个画刷,并且选入设备环境。CBrush *oldbrush;/保留旧画刷C

17、Brush brush(HS_CROSS,RGB(0,0,0);/创建画刷oldbrush=pDC-SelectObject(&brush);/选入设备环境/画图pDC-SelectObject(&oldbrush); /恢复旧画刷分析:上面的例子首先创建一个新画刷,在选入设备环境时保存旧画刷,然后进行画图操作,在结束时恢复画刷。10.2.3 绘图相关的数据类型在MFC定义了一些与绘图相关的数据类型,下面对这些数据类型进行介绍。1COLORREF这是一个32位的数据类型,它用8位的十六进制数据值0 x00bbggrr表示一个RGB颜色值,每个分量的最大值为0 xff,即255。

18、在应用中,经常利用一个COLORREF类型的值得到3种颜色,使用如下宏:BYTE GetRValue(DWORD rgb);/获取红色分量BYTE GetGValue(DWORD rgb);/获取绿色分量BYTE GetBValue(DWORD rgb);/获取蓝色分量有时需要定义一个COLORREF类型的变量,如下所示。COLORREF RGB(BYTE red,BYTE green,BYTE blue);定义COLORREF可以使用RGB()函数,在上面已经看到该函数的使用方法。在使用颜色对话框的时候,单击“确定”按钮以后会返回一个COLORREF类型的数值,即所选颜色。2CPointCP

19、oint类是从结构POINT派生,它封装了一个点的坐标,具有两个整型数据成员:x,y。CPoint类重载了几个运算符,包括=、!=、+=、=、+、,这样对坐标的操作就十分方便了。CPoint类构造函数如下:CPoint();CPoint( int initX, int initY );CPoint( POINT initPt );CPoint( SIZE initSize );CPoint( DWORD dwPoint );3CSizeCSize派生于SIZE结构,它具有整型成员cx,cy,用来表示距离及相对位置。CSize类重载了几个运算符,包括=、!=、+=、-=、+、,其与CPoint的

20、构造函数相似,如下所示。CSize();CSize( int initCX, int initCY );CSize( SIZE initSize );CSize( POINT initPt );CSize( DWORD dwSize );4CRectCRect是从RECT派生而来,具有left、top、right和bottom 4个整型数据成员,用来表示一个矩形区域。一般情况下要求此区域必须存在,即左边的坐标小于右边的坐标,上边的坐标小于下边的坐标。CRect中包含一些成员函数,其中较为常用的如表10.2所示。表10.2 CRect的成员函数函函 数数说说 明明int Width() cons

21、t;得到宽度得到宽度int Height() const;得到高度得到高度CSize Size() const;得到大小得到大小const CPoint& TopLeft() const;得到左上角坐标得到左上角坐标const CPoint& BottomRight() const;得到右下角坐标得到右下角坐标BOOL SubtractRect( LPCRECT lpRectSrc1, LPCRECT lpRectSrc2 );两个矩形相并两个矩形相并BOOL PtInRect( POINT point ) const;判断点是否在矩形区域内判断点是否在矩形区域内10.3 绘

22、图 实 例上面介绍了Windows绘图的基础知识,本节结合实例讲解绘图程序的操作步骤,同时讲解窗口的刷新和重绘问题。10.3.1 绘图函数介绍在CDC类中封装了大部分的绘图函数,通过使用这些函数可以方便地绘制各种各样的图形。下面对这些函数进行分类介绍。1绘制点和线绘制点是绘图中最基本的操作,CDC类中提供了两个函数可以在指定的坐标上绘制一个点,函数声明如下:COLORREF SetPixel( int x, int y, COLORREF crColor );COLORREF SetPixel( POINT point, COLORREF crColor );上面的两个函数是设置某一点的颜色,

23、其中第一种形式的两个整型参数代表横、纵坐标,crColor代表一个颜色值。第二种形式的不同之处在于使用POINT变量表示点。上面的两个函数返回的是设置点的颜色。BOOL SetPixelV(int x, int y, COLORREF crColor);BOOL SetPixelV( POINT point, COLORREF crColor );上面的函数与SetPixel()函数的参数意义完全一致,同时函数作用也相同。只不过该函数的返回值为函数调用是否成功的标志。说明:SetPixelV()函数只是返回一个调用是否成功的标志值,因此,一般情况下该函数比SetPixe()函数要快一些。绘制线

24、也是绘图中的基本操作,CDC类中提供两个成员函数MoveTo()和LineTo()实现划线操作。函数声明如下:CPoint MoveTo( int x, int y );CPoint MoveTo( POINT point );上面的两个函数是设置直线的起点。其中MoveTo()函数是定义一个起始点,第一种函数的点由两个整数表示,而第二种则是一个POINT结构表示。BOOL LineTo( int x, int y );BOOL LineTo( POINT point );上面的函数是画直线,参数是直线的另一个点。在需要绘制直线时,需要先调用MoveTo指定直线的起点,接着调用LineTo指定

25、直线的终点,这时程序会将起点和终点连接起来,直线的样式应该是当前的设备环境选择的。绘制完成后,终点又变成当前的起点,此时可以继续调用LineTo绘制直线。如果需要绘制一条折线,利用上面的操作需要多步才可以完成,CDC中提供了一个绘制折线的函数,其声明如下:BOOL Polyline( LPPOINT lpPoints, int nCount );BOOL PolyPolyline( const POINT* lpPoints, const DWORD* lpPolyPoints, int nCount );BOOL PolylineTo( const POINT* lpPoints, int

26、nCount );第一个函数绘制折线,参数lpPoints是一个点的数组,绘制折线时会将数组中相邻的点相连,nCount表示数组中点的个数。第二个函数可以绘制多条折线,参数lpPolyPoints表示每条折线点的个数,nCount表示折线数目。PolylineTo则使用当前位置绘制折线。2绘制曲线CDC中提供了Arc()和ArcTo()函数绘制圆弧,函数声明如下:BOOL Arc( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 );BOOL Arc( LPCRECT lpRect, POINT ptStart, P

27、OINT ptEnd );其中第一种形式利用整数的形式指定点的坐标。第二种形式则利用LPCRECT指定矩形区域,而利用POINT指定圆弧起始点和终点的坐标。BOOL ArcTo( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 );BOOL ArcTo( LPCRECT lpRect, POINT ptStart, POINT ptEnd );Arc()函数所画的椭圆弧线由给定的矩形边框所形成的椭圆定义。第一种形式是指定矩形的左上角坐标(x1,y1),右下角坐标(x2,y2),然后是弧线的起点和终点坐标(x3,y3)

28、、(x4,y4)。第二种形式则是由LPCRECT类型指定了矩形的区域,然后给出弧线的起点和终点。ArcTo()函数使用了当前位置,它会将当前位置与起始点连接,其他与Arc相同。3绘制矩形和多边形CDC类中的Rectangle()函数和RoundRect()函数可以分别绘制矩形和圆角矩形,函数声明如下:BOOL Rectangle( int x1, int y1, int x2, int y2 );BOOL Rectangle( LPCRECT lpRect );第一种函数使用了整数表示两个点,即矩形的左上角点和右下角点。而第二种形式则是使用了LPCRECT表示一个矩形区域。BOOL Round

29、Rect( int x1, int y1, int x2, int y2, int x3, int y3 );BOOL RoundRect( LPCRECT lpRect, POINT point );这两个函数都需要参数表示绘制矩形的区域。其中第一种形式完全使用整型变量描述整个区域范围。而第二种形式而采用了LPRECT和POINT两种数据结构。CDC类中还提供了绘制多边形的函数,函数声明如下:BOOL Polygon( LPPOINT lpPoints, int nCount );Polygon()函数可以用来绘制多边形,参数lpPoints指定了多边形顶点的坐标,而nCount指定了多边形

30、的顶点个数。上面介绍了常见的绘图函数,在下面将会给出操作实例。10.3.2 刷新/重绘图形图形的刷新是绘图中必须考虑的问题,图形的刷新包括刷新的请求、系统对刷新请求的响应。而重绘则是解决刷新问题的一个很好的办法,即在刷新请求时重新绘制图形。1刷新请求在绘制图形的时候,在应用程序的客户区绘制一个图形,但是当用户单击菜单或者切换到其他应用程序窗口时,绘制的图形被全部或部分覆盖掉。那么当切换回来时,应用程序如何恢复被覆盖掉的部分呢?在应用程序中,用户的大部分操作都在用户区内完成,因此上面的问题会十分常见。在调整窗口大小、窗口移动或者被其他窗口覆盖时,都必须刷新视图。刷新请求是应用程序出现上面的某种情

31、况时,应用程序会发送一个WM_PAINT消息,通知应用程序图形需要被刷新。2刷新请求的响应当应用程序的窗口需要刷新时,应用程序会发送WM_PAINT消息通知应用程序。应用程序接收到此消息以后,会调用相应的消息处理函数对刷新请求进行处理。有些情况下,系统会自动对刷新请求进行处理,例如光标的穿过等。系统对刷新请求的响应可以分为以下两类:(1)系统自动完成刷新。对于一些特殊情况,系统会自动完成刷新请求而不需要应用程序进行处理,此种情况如下:光标穿过用户区。图标拖过用户区。(2)应用程序处理。在窗口移动或者窗口被覆盖的情况下,应用程序发送WM_PAINT消息通知应用程序请求刷新处理,这时应用程序需要进

32、行窗口的重绘。这是最常见的刷新请求的处理流程。3窗口的重绘窗口的重绘是处理刷新请求最常见的方法。在程序中,把图形处理程序放在消息WM_PAINT模块中,这样一旦应用程序接收到刷新请求就可以迅速进行重绘图形。注意:图形的重绘并不是说必须把图形处理程序放在WM_PAINT消息响应函数中,而一般情况下是放在OnDraw()函数中,这是因为WM_PAINT消息处理会自动调用OnDraw()函数。10.3.3 创建简单绘图程序上面介绍了绘图的基本知识,下面给出一个绘图的具体实例。【示例10.4】 在单文档应用程序中添加菜单,实现绘制多种图形的功能。操作步骤如下所述。(1)创建一个基于单文档的应用程序。(

33、2)添加菜单资源,添加两个主菜单,“绘制图形”和“颜色选择”,其下拉菜单分别包含如下命令。“绘制图形”:“弧线”、“直线”、“矩形”。“颜色选择”:“线条颜色”、“填充颜色”。(3)为了记录菜单命令和颜色,在CTestView中添加变量如下所示。BOOL arcflag;/是否画弧线标志BOOL lineflag;/是否画直线标志BOOL reflag;/是否画矩形标志COLORREF linecolor;/线条颜色COLORREF incolor;/填充颜色并在CTestView的构造函数中进行初始化。arcflag=false;lineflag=false;reflag=false;lin

34、ecolor=RGB(0,255,255);/颜色变量incolor=RGB(0,255,255);(4)利用类向导添加选择绘制图形的下拉菜单命令的消息映射,编写函数体,代码如下:分析:上面的代码是当单击了一个菜单命令时,记录下单击的是哪一个菜单,并将其它两个菜单的标志清空。(5)利用类向导添加菜单更新的消息映射,即设置菜单状态选中在菜单前面画上“”。代码如下:由于在单击时已经设置好各个标志,所以上面的函数只要利用其标志进行设置就可以了。(6)利用类向导添加选择颜色下拉菜单的命令的消息映射,编写函数体,代码如下:分析:上面是当选择菜单命令时,首先弹出颜色对话框选择颜色,并且保存所选颜色。(7)

35、上面已经设置好菜单命令,下面对画图操作进行介绍。为了保存鼠标按下、弹起的坐标,并记录鼠标的状态,在CTestView中添加成员变量如下所示。CPoint start;/起始位置CPoint end;/终止位置BOOL flag;/鼠标按下标志(8)利用类向导在CTestView类中添加鼠标按下、移动和弹起的消息映射,编写函数体,代码如下:注意:在鼠标移动过程必须利用OnDraw()函数进行画图。如果在该函数中画图,则会出现屏幕上多个蝶影的现象。分析:在鼠标按下时,需要记录鼠标的坐标,并且将鼠标按下标志flag设置为true。在鼠标移动过程中,根据菜单的命令及鼠标当前的坐标绘制图形。需要注意的是

36、,这时并没有根据所选颜色进行画图,所以此时的图形为黑色,无填充色。鼠标弹起时,记录鼠标的坐标,将flag赋值为false,并且利用函数Invalidate();更新视图。这时程序会调用CTestView:OnDraw()函数,因此真正的画图操作在CTestView:OnDraw()函数中实现。(9)在CTestView:OnDraw()中添加代码如下:(10)编译、连接,运行结果如图10.2和图10.3所示。图10.2 运行结果图10.3 “绘制图形”下拉菜单上面的例子是利用了设备环境的概念进行画图操作,其中使用了各种画图函数。在应用中应注意鼠标按下、移动和弹起3个动作的关系。鼠标按下开始画图

37、,而移动时应实时画图,否则在移动时不会出现图形,直观上很别扭。鼠标弹起后则是完成真正的画图操作。10.3.4 使用区域绘制图形前面介绍了使用一般绘图函数绘制各种图形的例子。在实际应用中经常使用CRgn类绘制一些复杂的图形。该类可以创建椭圆、矩形或者多边形区域,并且可以将这些区域进行几何运算生成更加复杂的区域。类CRgn的成员函数可以创建一个几何区域,同时对区域可以进行常见的几何运算,其常用的函数如表10.3所示。表10.3 CRgn的常用成员函数函函 数数说说 明明BOOL CreateRectRgn( int x1, int y1, int x2, int y2);BOOL CreateRe

38、ctRgnIndirect( LPCRECT lpRect);创建矩形区域创建矩形区域BOOL CreateEllipticRgn( int x1, int y1, int x2, int y2 );BOOL CreateEllipticRgnIndirect( LPCRECT lpRect );创建椭圆区域创建椭圆区域BOOL CreatePolygonRgn( LPPOINT lpPoints, int nCount, int nMode );创建多边形区域创建多边形区域BOOL CreatePolyPolygonRgn( LPPOINT lpPoints, LPINT lpPolyCou

39、nts, int nCount, int nPolyFillMode );创建多个多边形区域创建多个多边形区域int CombineRgn( CRgn* pRgn1, CRgn* pRgn2, int nCombineMode );合并区域合并区域int CopyRgn( CRgn* pRgnSrc );复制区域复制区域上面是CRgn类常用的成员函数,其中CombineRgn()函数是进行几何计算的函数,其参数的取值如下所示。RGN_AND:两个区域相交。RGN_COPY:复制区域1。RGN_DIFF:得到区域1中不包含在区域2中的部分。RGN_OR:合并两个区域。RGN_XOR:两个区域不相

40、交部分。注意:CombineRgn()函数和CopyRgn()函数的返回值为整型变量,代表具体操作的结果。包括区域是否为空,操作是否成功等。上面介绍了CRgn类进行区域操作的基本函数,在应用中可以设置区域以后,利用函数进行计算得到其他区域。下面通过一个实例介绍CRgn的用法。【示例10.5】 在单文档界面上输出一个“弯月”的图形。分析:画出“弯月”模型可以利用CRgn类的多个对象进行,具体步骤如下:(1)创建一个基于单文档的应用程序。(2)在OnDraw()函数中输出图形,因此在OnDraw()函数中添加代码,具体代码如下:分析:上面的代码首先是创建两个圆形区域,然后利用函数得到区域1中不在区

41、域2中的部分,即“弯月”,然后利用函数FrameRgn画出此模型。(3)编译、连接,运行结果如图10.4所示。图10.4 运行结果分析:上面利用CRgn实现了画“弯月”模型。在实际应用中可以利用CRgn实现不规则区域的窗口,此时只要利用CWnd: SetWindowRgn()函数就可以实现不规则窗口的输出。感兴趣的读者可以再使用该函数编写一个不规则窗口的应用程序。10.4 文本在Windows中经常利用GDI进行文本的输出。文本的输出与图形的输出并没有本质的区别,两者是十分接近的,甚至说可以把文本看做图形来处理。当然在MFC中对文本的操作进行了封装,使得对文本的操作更加方便。10.4.1 字体

42、的结构Windows系统中提供了一些常用的字体,在应用中可以利用字体句柄将系统的字体选入设备环境,然后就可以利用该字体进行输入输出。在Windows中,利用LOGFONT对字体进行描述,LOGFONT的结构如下:typedef struct tagLOGFONT / lf LONG lfHeight; /字体的高度 LONG lfWidth; /字体的宽度 LONG lfEscapement; /字体相对于x轴的倾斜度 LONG lfOrientation; /字体基准线与x轴之间夹角 LONG lfWeight; /字体的粗细,取值01000 BYTE lfItalic; /非零表示斜体 B

43、YTE lfUnderline; /非零表示有下划线 BYTE lfStrikeOut; /非零表示有删除线 BYTE lfCharSet; /字体字符集 BYTE lfOutPrecision; /字体的输出精度 BYTE lfClipPrecision; /字体的裁剪精度 BYTE lfQuality; /字体的输出质量 BYTE lfPitchAndFamily; /字符间距 TCHAR lfFaceNameLF_FACESIZE; /字体名称 LOGFONT; 上面介绍了Windows中字体的一般描述形式,在MFC中,利用CFont类对字体进行了封装,可以利用该类方便地创建字体并且选入

44、设备环境,然后可以使用。注意:LOGFONT结构中包含了所要创建的字体中的全部信息,需要注意的是ifEscapement成员制定了所创建的字体与水平方向所倾斜的角度,该成员变量角度的单位是十分之一度而不是度。同时为了保证所有的字体按照一个方向旋转,一定要设置ifEscapenent的CLIP_LH_ANGLES位,否则字体有可能向反方向旋转。10.4.2 创建字体在MFC中,利用CFont类对字体进行了封装,利用其成员函数可以创建字体,创建字体的函数如下:BOOL CreateFontIndirect(const LOGFONT* lpLogFont );BOOL CreateFont( in

45、t nHeight, int nWidth, int nEscapement, int nOrientation, int nWeight, BYTE bItalic, BYTE bUnderline, BYTE cStrikeOut, BYTE nCharSet, BYTE nOutPrecision, BYTE nClipPrecision, BYTE nQuality, BYTE nPitchAndFamily, LPCTSTR lpszFacename );BOOL CreatePointFont( int nPointSize, LPCTSTR lpszFaceName, CDC*

46、pDC = NULL ); BOOL CreatePointFontIndirect( const LOGFONT* lpLogFont, CDC* pDC = NULL );利用上面的函数可以创建一个字体,其中各个参数的意义十分明显,在此不再介绍。【示例10.6】 利用上面的函数创建一个字体。代码如下:上面代码段利用CFont的成员函数创建了字体。在对话框程序设计中,曾经介绍了Windows通用对话框里的“字体”对话框,利用此对话框也可以创建一个字体。在单击“确定”按钮以后,可以利用函数得到所选字体。【示例10.7】 利用“字体”对话框的返回值创建一个字体,程序段如下:分析:上面的程序段可以

47、弹出“字体”对话框,当用户点击“确定”按钮以后,可以创建用户所选的字体。上面介绍了创建字体的方法,在应用程序中可以选择一种创建字体的方法进行使用。10.5 文 本 输 出上面介绍了字体的创建,在Windows中经常对字体进行输出。字体的输出需要对字体的输出格式等进行设置以输出不同的样式,本节对字体的输出函数和文本格式进行介绍。10.5.1 文本输出函数在进行文本操作时,经常使用的就是文本输出函数,在CDC类中提供了4个文本输出函数,其形式如下:virtual BOOL TextOut( int x, int y, LPCTSTR lpszString, int nCount );BOOL Te

48、xtOut( int x, int y, const CString& str );上面的函数是在(x,y)坐标处输出文本,其中nCount表示输出文本字节数。virtual BOOL ExtTextOut( int x, int y, UINT nOptions, LPCRECT lpRect, LPCTSTR lpszString, UINT nCount, LPINT lpDxWidths );BOOL ExtTextOut( int x, int y, UINT nOptions, LPCRECT lpRect, const CString& str, LPINT lp

49、DxWidths );这种函数输出形式则是在(x,y)坐标处、指定的矩形区域内输出文本。nOptions表示矩形类型,取值为ETO_CLIPPED或ETO_OPAQUE。lpRect表示矩形区域,nCount表示输出字节数,lpDxWidths指定字符间隔。virtual CSize TabbedTextOut( int x, int y, LPCTSTR lpszString, int nCount, int nTabPositions, LPINT lpnTabStopPositions, int nTabOrigin );CSize TabbedTextOut( int x, int y

50、, const CString& str, int nTabPositions, LPINT lpnTabStopPositions, int nTabOrigin );这种函数输出形式则为根据数组lpnTabStopPositions设置输出文本中制表位的位置,参数nTabPositions表示数组的大小。virtual int DrawText( LPCTSTR lpszString, int nCount, LPRECT lpRect, UINT nFormat );int DrawText( const CString& str, LPRECT lpRect, UINT

51、 nFormat );这种函数输出形式按照nFormat形式输出文本。【示例10.8】 文本输出函数的使用。在单文档的界面上输出一些文本。在单文档应用程序的CTestView:OnDraw()添加如下代码:运行结果如图10.5所示。图10.5 运行结果上面是文本输出的例子,在Windows中对文本的输出也是图形的输出。当然MFC中对一些东西进行了封装,这样使得文本输出更加简单。10.5.2 设置文本格式在进行文本输出操作时经常需要考虑文本输出的格式问题,例如文本的背景色,字符间隔。默认情况下,背景色为白色,文本为黑色,这些可以利用CDC类的函数进行设置,实现输出的不同效果。CDC中提供的函数如

52、下:virtual COLORREF SetTextColor( COLORREF crColor );/设置背景色COLORREF GetTextColor() const;/获取文本颜色COLORREF GetBkColor() const;/获取背景色virtual COLORREF SetBkColor( COLORREF crColor );/设置背景色【示例10.9】 上面的程序段在进行文本输出之前,首先设置文本颜色如下:pDC-SetTextColor(RGB(200,0,0);利用上面的函数设置文本的颜色,则此时文本的输出颜色为红色。说明:文本格式可以在任何界面上进行设置,例如

53、利用SetFont()函数对编辑框内字体进行设置等。在DrawText()函数中还可以指定文本的对齐方式,而在CDC类中还提供了SetTextAlign()函数和GetTextAlign()函数,用来设置和获取默认的文本对齐方式。两个函数的函数原型如下:UINT SetTextAlign( UINT nFlags );UINT GetTextAlign() const;在SetTextAlign()函数中,nFlags参数常用的取值如下所示。TA_CENTER:以中点方式对齐。TA_LEFT:左侧对齐。TA_RIGHT:右侧对齐。TA_BASELINE:按基准线上下对齐。TA_BOTTOM:底

54、部对齐。TA_TOP:顶部对齐。TA_NOUPDATECP:不做更新处理。TA_UPDATECP:更新处理。说明:上面的各个对齐方式指的是在矩形区域内输出文字时,对该矩形区域的对齐方式。例如 左侧对齐,是指以矩形区域的左侧对齐。在CDC中还提供了处理字符间距的函数int SetTextCharacterExtra( int nCharExtra );和int GetTextCharacterExtra() const;这两个函数对输出字符的间距进行控制。【示例10.10】 利用文本格式控制函数在单文档应用程序的界面上输出文本。了解常用的文本格式控制函数的使用。(1)创建一个基于单文档的应用程序

55、。(2)在OnDraw()函数中实现文本的输出,代码如下:(3)编译、连接,运行程序,在单文档界面上输出两行文本。运行结果如图10.6所示。图10.6 运行结果10.6 打印在现代的应用程序中,大多数的应用程序都支持了打印和打印预览的功能。如果使用API函数对打印机进行访问,那么实现打印功能是十分困难的。而在MFC中将打印功能封装起来,这样实现打印功能就变得十分容易和方便了。10.6.1 单页打印在利用向导生成单文档和多文档应用程序的过程中,用户可以选择应用程序是否支持打印和打印预览功能。在利用类向导新建一个基于单文档的应用程序的过程中,在向导的第4步,如图10.7所示。用户可以根据需要选择是

56、否支持打印和打印预览功能。图10.7 向导第4步当选中了Printing and print view复选框以后,应用程序就会支持打印和打印预览的功能。下面首先查看向导生成的打印和打印预览功能的效果。【示例10.11】 利用类向导生成打印和打印预览功能。在CTestView:OnDraw()函数中输出一些图形,代码如下:分析:上面的代码在客户区上画出几个圆,编译、连接,运行结果如图10.8所示。此时选择“文件”|“打印预览”命令,弹出了打印预览的界面,如图10.9所示。图10.8 运行结果图10.9 打印预览说明:在向导中建立应用程序的最后一步可以设置CTestView的基类为CScrollV

57、iew类。此时会自动添加竖直滚动条的功能。分析:可以看到虽然向导生成了打印预览的功能,但是打印预览的效果与需要的差别很大。预览的界面上显示的图形很小。这是因为打印机和屏幕显示的分辨率不同,在Windows应用程序中使用的是MM_TEXT映射模式。该模式使用的是逻辑单位,因此打印预览时的显示就比屏幕上的要小一些。为了解决这个问题,可以使用MM_LOENGLISH模式,该模式设置坐标为0.01英寸,因此可以实现正确大小的输出。例如在上面的代码,首先前面利用SetMapMode(int nMode)函数设置为MM_LOENGLISH模式,注意此时x轴坐标向右为正方向,y轴坐标向上为正方向,所以画椭圆的y坐标值应该取反。此时的屏幕上的输出与设置MM_TEXT映射模式基本类似,但打印预览功能已经实现。此时的预览如图10.10所示。图10.10 改变映射模式后的打印预览分析:可见上面设置为MM_LOENGL

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论