第7章图形文本和位图

上传人:人*** 文档编号:579357851 上传时间:2024-08-26 格式:PPT 页数:84 大小:431.02KB
返回 下载 相关 举报
第7章图形文本和位图_第1页
第1页 / 共84页
第7章图形文本和位图_第2页
第2页 / 共84页
第7章图形文本和位图_第3页
第3页 / 共84页
第7章图形文本和位图_第4页
第4页 / 共84页
第7章图形文本和位图_第5页
第5页 / 共84页
点击查看更多>>
资源描述

《第7章图形文本和位图》由会员分享,可在线阅读,更多相关《第7章图形文本和位图(84页珍藏版)》请在金锄头文库上搜索。

1、第第7章章 图形、文本和位图图形、文本和位图7.1 概述概述Visual C+的CDC(Device Context,设备环境)类是MFC中最重要的类之一,它封装了绘图所需要的所有函数,是用户编写图形和文字处理程序必不可少的。当然,绘制图形和文字时还必须指定相应的设备环境。设备设备环境是由环境是由Windows保存的一个数据结构,该结构包含应用程保存的一个数据结构,该结构包含应用程序向设备输出时所需要的信息。序向设备输出时所需要的信息。7.1.1 设备环境类设备环境类(1) CPaintDC比较特殊,它的构造函数和析构函数都是针对OnPaint进行的,但用户一旦获得相关的CDC指针,就可以将它

2、当成任何设备环境(包括屏幕、打印机)指针来使用。CPaintDC类的构造函数会自动调用BeginPaint,而它的析构函数则会自动调用EndPaint。(2) CClientDC只能在窗口的客户区(不包括边框、标题栏、菜单栏以及状态栏)中进行绘图,点(0,0)通常指的是客户区的左上角。而CWindowDC允许在窗口的任意位置中进行绘图,点(0,0)指整个窗口的左上角。CWindowDC和CClientDC构造函数分别调用GetWindowDC和GetDC,但它们的析构函数都是调用ReleaseDC函数。(3) CMetaFileDC封装了在一个Windows图元文件中绘图的方法。图元文件是一系

3、列与设备无关的图片的集合,由于它对图象的保存比像素更精确,因而往往在要求较高的场合下使用,例如AutoCAD的图像保存等。目前的Windows已使用增强格式(enhanced-format)的32位图元文件来进行操作。7.1.2 坐标映射坐标映射在讨论坐标映射之前,先来看看下列语句:pDC-Rectangle(CRect(0,0,200,200);它是在某设备环境中绘制出一个高为200个像素,宽也为200个像素的方块。由于默认的映射模式是MM_TEXT,其逻辑坐标(在各种映射模式下的坐标)和设备坐标(显示设备或打印设备坐标系下的坐标)相等。因此这个方块在1024 x 768的显示器上看起来要比

4、在640 x 480的显示器上显得小一些,而且若将它打印在600dpi精度的激光打印机上,这个方块就会显得更小了。如表7.1所示。表表7.1 映射模式映射模式7.1.2 坐标映射坐标映射例例Ex_Draw 通过设置窗口和视口大小来改变显示的比例通过设置窗口和视口大小来改变显示的比例(1) 用MFC AppWizard创建一个默认的单文档应用程序Ex_Draw。(2) 在CEx_DrawView:OnDraw函数中添加下列代码:void CEx_DrawView:OnDraw(CDC* pDC)CEx_DrawDoc* pDoc = GetDocument();ASSERT_VALID(pDoc

5、);CRect rectClient;GetClientRect(rectClient); / 获得当前窗口的客户区大小pDC-SetMapMode(MM_ANISOTROPIC); / 设置MM_ANISOTROPIC映射模式pDC-SetWindowExt(1000,1000); / 设置窗口范围pDC-SetViewportExt(rectClient.right,-rectClient.bottom);/ 设置视口范围pDC-SetViewportOrg(rectClient.right/2,rectClient.bottom/2);/ 设置视口原点pDC-Ellipse(CRect(

6、-500,-500,500,500);例例Ex_Draw(3) 编译运行,结果如图7.1所示。图7.1 改变显示比例7.1.3 CPoint、CSize和和CRect在图形绘制操作中,常常需要使用MFC中的CPoint、CSize和CRect等简单数据类由于CPoint(点)、CSize(大小)和CRect(矩形)是对Windows的POINT、SIZE和RECT结构的封装,因此它们可以直接使用各自结构的数据成员,如下所示:typedef struct tagPOINT typedef struct tagSIZE LONG x; / 点的x坐标 int cx; / 水平大小 LONG y;

7、/ 点的y坐标 int cy; / 垂直大小 POINT; SIZE;typedef struct tagRECT LONG left;/ 矩形左上角点的x坐标 LONG top; / 矩形左上角点的y坐标 LONG right; / 矩形右下角点的x坐标 LONG bottom; / 矩形右下角点的y坐标 RECT;7.1.3 CPoint、CSize和和CRect1. CPoint、CSize和和CRect类的构造函数类的构造函数CPoint类带参数的常用构造函数原型如下: CPoint( int initX, int initY ); CPoint( POINT initPt );其中,

8、initX和initY分别用来指定CPoint的成员x和y的值。initPt用来指定一个POINT结构或CPoint对象来初始化CPoint的成员。CSize类带参数的常用构造函数原型如下: CSize( int initCX, int initCY ); CSize( SIZE initSize ); 其中,initCX和initCY用来分别设置CSize的cx和cy成员。initSize用来指定一个SIZE结构或CSize对象来初始化CSize的成员。CRect类带参数的常用构造函数原型如下: CRect( int l, int t, int r, int b ); CRect( cons

9、t RECT& srcRect ); CRect( LPCRECT lpSrcRect ); CRect( POINT point, SIZE size ); CRect( POINT topLeft, POINT bottomRight );7.1.3 CPoint、CSize和和CRect2. CRect类的常用操作类的常用操作由于一个CRect类对象包含用于定义矩形的左上角和右下角点的成员变量,因此在传递LPRECT、LPCRECT或RECT结构作为参数的任何地方,都可以使用CRect对象来代替。 CRect类的操作函数有很多,这里只介绍矩形的扩大、缩小以及两个矩形的“并”和“交”操作,

10、更多的常用操作如表7.2所示。表表7.2 CRect类常用的成员函数类常用的成员函数7.1.3 CPoint、CSize和和CRect2. CRect类的常用操作类的常用操作成员函数InflateRect和DeflateRect用来扩大和缩小一个矩形。由于它们的操作是相互的,也就是说,若指定InflateRect函数的参数为负值,那么操作的结果是缩小矩形,因此下面只给出InflateRect函数的原型:void InflateRect( int x, int y );void InflateRect( SIZE size );void InflateRect( LPCRECT lpRect )

11、;void InflateRect( int l, int t, int r, int b );其中,x用来指定扩大CRect左、右边的数值。y用来指定扩大CRect上、下边的数值。size中的cx成员指定扩大左、右边的数值,cy指定扩大上、下边的数值。lpRect的各个成员用来指定扩大每一边的数值。l、t、r和b分别用来指定扩大CRect左、上、右和下边的数值。 7.1.3 CPoint、CSize和和CRect2. CRect类的常用操作类的常用操作成员函数IntersectRect和UnionRect分别用来将两个矩形进行相交和合并,当结果为空时返回FALSE,否则返回TRUE。它们的原

12、型如下:BOOL IntersectRect( LPCRECT lpRect1, LPCRECT lpRect2 );BOOL UnionRect( LPCRECT lpRect1, LPCRECT lpRect2 );其中,lpRect1和lpRect2用来指定操作的两个矩形。例如:CRect rectOne(125, 0, 150, 200);CRect rectTwo( 0, 75, 350, 95);CRect rectInter;rectInter.IntersectRect(rectOne, rectTwo);/ 结果为(125, 75, 150, 95)ASSERT(rectIn

13、ter = CRect(125, 75, 150, 95);rectInter.UnionRect (rectOne, rectTwo);/ 结果为(0, 0, 350, 200)ASSERT(rectInter = CRect(0, 0, 350, 200);7.1.4 颜色和颜色对话框颜色和颜色对话框在MFC中,CDC使用的是RGB颜色空间,即选用红(R)、绿(G)、蓝(B)三种基色分量,通过对这三种基色不同比例的混合,可以得到不同的彩色效果。并且,MFC使用COLORREF数据类型来表示一个32位的RGB颜色,它也可以用下列的十六进制表示: 0x00bbggrr 此形式的rr、gg、bb

14、分别表示红、绿、蓝三个颜色分量的16进制值,最大为0xff。在具体操作RGB颜色时,还可使用下列的宏操作: GetBValue 获得32位RGB颜色值中的蓝色分量 GetGValue 获得32位RGB颜色值中的绿色分量 GetRValue 获得32位RGB颜色值中的红色分量 RGB 将指定的R、G、B分量值转换成一个32位的RGB颜色值。MFC的CColorDialog类为应用程序提供了颜色选择通用对话框,如图7.2所示。图7.2 颜色对话框7.1.4 颜色和颜色对话框颜色和颜色对话框CColorDialog类具有下列的构造函数:CColorDialog( COLORREF clrInit =

15、 0, DWORD dwFlags = 0, CWnd* pParentWnd = NULL );其中,clrInit用来指定选择的默认颜色值,若此值没指定,则为RGB(0,0,0) (黑色)。pParentWnd用来指定对话框的父窗口指针。dwFlags用来表示定制对话框外观和功能的系列标志参数。它可以是下列值之一或”|”组合:CC_ANYCOLOR 在基本颜色单元中列出所有可得到的颜色 CC_FULLOPEN 显示所有的颜色对话框界面。若此标志没有被设定,则用户单击“规定自定义颜色”按钮才能显示出定制颜色的界面 CC_PREVENTFULLOPEN 禁用“规定自定义颜色”按钮 CC_SHO

16、WHELP 在对话框中显示“帮助”按钮 CC_SOLIDCOLOR 在基本颜色单元中只列出所得到的纯色当对话框“OK”退出(即DoModal返回 IDOK)时,可调用下列成员获得相应的颜色。 COLORREF GetColor( ) const;/ 返回用户选择的颜色。 void SetCurrentColor( COLORREF clr );/ 强制使用clr作为当前选择的颜色 static COLORREF * GetSavedCustomColors( );/ 返回用户自己定义颜色7.1.5 图形设备接口图形设备接口Windows为设备环境提供了各种各样的绘图工具,例如用于画线的“画笔”

17、、填充区域的“画刷”以及用于绘制文本的“字体”。MFC封装了这些工具,并提供相应的类来作为应用程序的图形设备接口GDI,这些类有一个共同的抽象基类CGdiObject,具体如表7.3所示。表表7.3 MFC的的GDI类类7.1.5 图形设备接口图形设备接口1. 使用使用GDI对象对象在选择GDI对象进行绘图时,往往遵循着下列的步骤:(1) 在堆栈中定义一个GDI对象(如CPen、CBrush对象),然后用相应的函数(如CreatePen、CreateSolidBrush)创建此GDI对象。但要注意:有些GDI派生类的构造函数允许用户提供足够的信息,从而一步即可完成对象的创建任务,这些类有CPe

18、n、CBrush。(2) 将构造的GDI对象选入当前设备环境中,但不要忘记将原来的GDI对象保存起来。(3)绘图结束后,恢复当前设备环境中原来的GDI对象。(4)由于GDI对象是在堆栈中创建中,当程序结束后,会自动删除程序创建的GDI对象。具体操作可像下面的代码过程:void CMyView:OnDraw( CDC* pDC )CPen penBlack; / 定义一个画笔变量penBlack.CreatePen( PS_SOLID, 2, RGB(0,0,0); / 创建画笔 / 将此画笔选入当前设备环境并保存原来的画笔CPen* pOldPen = pDC-SelectObject( &p

19、enBlack );/ 用此画笔绘图pDC-MoveTo(.);pDC-LineTo(.);/ 其他绘图函数pDC-SelectObject( pOldPen ); / 恢复设备环境中原来的画笔7.1.5 图形设备接口图形设备接口2. 库存的库存的GDI对象对象除了自定义的GDI对象外,Windows还包含了一些预定义的库存GDI对象。由于它们是Windows系统的一部分,因此用户用不着删除它们。CDC的成员函数SelectStockObject可以把一个库存对象选入当前设备环境中,并返回原先被选中的对象指针,同时使原先被选中的对象从设备环境中分离出来。如下面的代码:void CEx_SDIV

20、iew:OnDraw( CDC* pDC )CPen newPen( PS_SOLID, 2, RGB(0,0,0) ) )pDC-SelectObject( &newPen ); pDC-MoveTo(.); pDC-LineTo(.);/ 其他绘图函数 pDC-SelectStockObject( BLACK_PEN );/ newPen被分离出来2. 库存的库存的GDI对象对象函数SelectStockObject可选用的库存GDI对象类型可以是下列值之一:BLACK_BRUSH 黑色画刷DKGRAY_BRUSH 深灰色画刷GRAY_BRUSH 灰色画刷HOLLOW_BRUSH 中空画刷

21、LTGRAY_BRUSH 浅灰色画刷NULL_BRUSH 空画刷WHITE_BRUSH 白色画刷BLACK_PEN 黑色画笔NULL_PEN 空画笔WHITE_PEN 白色画笔DEVICE_DEFAULT_FONT 设备默认字体SYSTEM_FONT 系统字体7.2 简单图形绘制简单图形绘制图形的绘制通常需要先创建画笔和画刷,然后调用相应的绘图函数。7.2.1 画笔画笔画笔是Windows应用程序中用来绘制各种直线和曲线的一种图形工具,它可分为修饰画笔和几何画笔两种类型。在这两种类型中,几何画笔的定义最复杂,它不但有修饰画笔的属性,而且还跟画刷的样式、阴影线类型有关,通常用在对绘图有较高要求的

22、场合。而修饰画笔只有简单的几种属性,通常用在简单的直线和曲线等场合。7.2.1 画笔画笔表表7.4 修饰画笔的风格修饰画笔的风格7.2.1 画笔画笔创建一个修饰画笔,可以使用CPen类的CreatePen函数,其原型如下:BOOL CreatePen( int nPenStyle, int nWidth, COLORREF crColor );其中,参数nPenStyle、nWidth、crColor分别用来指定画笔的风格、宽度和颜色。此外,还有一个CreatePenIndirect函数也是用来创建画笔对象,它的作用与CreatePen函数是完全一样的,只是画笔的三个属性不是直接出现在函数参数

23、中,而是通过一个LOGPEN结构间接地给出。BOOL CreatePenIndirect( LPLOGPEN lpLogPen );此函数用由LOGPEN结构指针指定的相关参数创建画笔,LOGPEN结构如下:typedef struct tagLOGPEN /* lgpn */ UINT lopnStyle;/ 画笔风格,同上 POINT lopnWidth; / POINT结构的y不起作用,而用x表示画笔宽度 COLORREF lopnColor;/ 画笔颜色 LOGPEN;7.2.2 画刷画刷画刷的属性通常包括填充色、填充图案和填充样式三种。画刷的填充色和画笔颜色一样,都是使用COLORR

24、EF颜色类型,画刷的填充图案通常是用户定义的8 8位图,而填充样式往往是CDC内部定义的一些特性,它们都是以HS_为前缀的标识,如图7.3所示:HS_BDIAGONALHS_CROSSHS_DIAGCROSSHS_FDIAGONAL HS_HORIZONTAL HS_VERTICAL图7.3 画刷的填充样式7.2.2 画刷画刷CBrush类根据画刷属性提供了相应的创建函数,例如创建填充色画刷和填充样式画刷的函数为CreateSolidBrush和CreateHatchBrush,它们的原型如下:BOOL CreateSolidBrush( COLORREF crColor ); / 创建填充色

25、画刷BOOL CreateHatchBrush( int nIndex, COLORREF crColor ); / 创建填充样式画刷其中,nIndex用来指定画刷的内部填充样式,而crColor表示画刷的填充色。与画笔相类似,也有一个LOGBRUSH 逻辑结构用于画刷属性的定义,并通过 CBrush的成员函数CreateBrushIndirect来创建,其原型如下:BOOL CreateBrushIndirect( const LOGBRUSH* lpLogBrush );其中,LOGBRUSH 逻辑结构如下定义:typedef struct tagLOGBRUSH / lb UINT lb

26、Style; / 风格 COLORREF lbColor; / 填充色 LONG lbHatch; / 填充样式 LOGBRUSH; 7.2.3 图形绘制图形绘制1. 画点、线画点、线(1) 画点是最基本的绘图操作之一,它是通过调用CDC:SetPixel或CDC:SetPixelV函数来实现的。这两个函数都是用来在指定的坐标上设置指定的颜色,只不过SetPixelV函数不需要返回实际像素点的RGB值;正是因为这一点,函数SetPixelV要比SetPixel快得多。COLORREF SetPixel( int x, int y, COLORREF crColor );COLORREF Set

27、Pixel( POINT point, COLORREF crColor );BOOL SetPixelV(int x, int y, COLORREF crColor);BOOL SetPixelV( POINT point, COLORREF crColor );实际显示像素的颜色未必等同于crColor所指定的颜色值,因为有时受设备限制,不能显示crColor所指定的颜色值,而只能取其近似值。与上述函数相对应的GetPixel函数是用来获取指定点的颜色。COLORREF GetPixel( int x, int y ) const;COLORREF GetPixel( POINT poi

28、nt ) const;1. 画点、线画点、线(2) 画线也是特别常用的绘图操作之一。CDC的LineTo和MoveTo函数就是用来实现画线功能的两个函数,通过这两个函数的配合使用,可完成任何直线和折线的绘制操作。这个当前位置还可用函数CDC:GetCurrentPosition来获得,其原型如下:CPoint GetCurrentPosition( ) const;LineTo函数正是经当前位置所在点为直线起始点,另指定直线终点,画出一段直线的。其原型如下:BOOL LineTo( int x, int y );BOOL LineTo( POINT point );7.2.3 图形绘制图形绘制

29、2. 折线折线除了LineTo函数可用来画线之外,CDC中还提供了一系列用于画各种折线的函数。它们主要是Polyline、PolyPolyline和PolylineTo。这三个函数中,Polyline和PolyPolyline既不使用当前位置,也不更新当前位置;而PolylineTo总是把当前位置作为起始点,并且在折线画完之后,还把折线终点所在位置设为新的当前位置。BOOL Polyline( LPPOINT lpPoints, int nCount );BOOL PolylineTo( const POINT* lpPoints, int nCount );这两个函数用来画一系列连续的折线。

30、参数lpPoints是POINT或CPoint的顶点数组;nCount表示数组中顶点的个数,它至少为2。BOOL PolyPolyline( const POINT* lpPoints, const DWORD* lpPolyPoints, int nCount );此函数可用来绘制多条折线。其中lpPoints同前定义,lpPolyPoints表示各条折线所需的顶点数,nCount表示折线的数目。7.2.3 图形绘制图形绘制3. 矩形和圆角矩形矩形和圆角矩形CDC提供的Rectangle和RoundRect函数分别用于矩形和圆角矩形的绘制,它们的原型如下:BOOL Rectangle( in

31、t x1, int y1, int x2, int y2 );BOOL Rectangle( LPCRECT lpRect );BOOL RoundRect( int x1, int y1, int x2, int y2, int x3, int y3 );BOOL RoundRect( LPCRECT lpRect, POINT point );参数lpRect的成员left,top,right,bottom分别表示x1,y1,x2,y2,point的成员x,y分别表示x3,y3;而x1,y1表示矩形的左上角坐标,x2,y2表示矩形的右上角坐标,x3,y3表示绘制圆角的椭圆大小,如图7.4所

32、示。图7.4 圆角矩形图7.5 多边形填充模式7.2.3 图形绘制图形绘制4. 设置多边形填充模式设置多边形填充模式多边形填充模式决定了图形填充时寻找填充区域的方法,有两种选择:ALTERNATE和WINDING。ALTERNATE模式是寻找相邻的奇偶边作为填充区域,而WINDING是按顺时针或逆时针进行寻找;一般情况,这两种模式的填充效果是相同的,但对于像五角星这样的图形,填充的结果大不一样,例如下面的代码,其结果如图7.5所示。.POINTpt5=247,10,230,90,290,35,210,30,275,85;CBrushbrush(HS_FDIAGONAL,RGB(255,0,0)

33、;CBrush* oldbrush=pDC-SelectObject(&brush);pDC-SetPolyFillMode(ALTERNATE);pDC-Polygon(pt,5);for(int i=0;iSetPolyFillMode(WINDING);pDC-Polygon(pt,5);pDC-SelectObject(oldbrush);brush.DeleteObject();代码中,SetPolyFillMode是CDC类的一个成员函数,用来设置填充模式,它的参数可以是ALTERNATE和WINDING。7.2.3 图形绘制图形绘制5. 多边形多边形前面已经介绍过折线的画法,而多

34、边形可以说就是由首尾相接的封闭折线所围成的图形。画多边形的函数Polygon原型如下:BOOL Polygon( LPPOINT lpPoints, int nCount );可以看出,Polygon函数的参数形式与Polyline函数是相同的。但也稍有一点小差异。例如,要画一个三角形,使用Polyline函数,顶点数组中就得给出四个顶点(尽管始点和终点重复出现),而用Polygon函数则只需给出三个顶点。与PolyPolyline可画多条折线一样,使用PolyPolygon函数,一次可画出多个多边形,这两个函数的参数形式和含义也一样。BOOL PolyPolygon( LPPOINT lpP

35、oints, LPINT lpPolyCounts, int nCount );7.2.3 图形绘制图形绘制6. 圆弧和椭圆圆弧和椭圆通过调用CDC的Arc函数可以画一条椭圆弧线或者整个椭圆。这个椭圆的大小是由其外接矩形(本身并不可见)所决定的。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 );这里,x1,y1,x2,y2或lpRect用来指定外接矩形的位置和大小,

36、而椭圆中心与点(x3,y3)或ptStart所构成的射线与椭圆的交点就成为椭圆弧线的起始点,椭圆中心与点(x4,y4)或ptEnd所构成的射线与椭圆的交点就成为椭圆弧线的终点。椭圆上弧线始点到终点的部分是要绘制的椭圆弧,如图7.6所示。图7.6 弧线中心外接矩形弧线(x1,y1)(x2,y2)起点坐标终点坐标7.2.3 图形绘制图形绘制7. 弦形和扇形弦形和扇形CDC类成员函数Chord和Pie是用来绘制弦形(图7.7)和扇形(图7.8),它们具有和Arc一样的参数。BOOL Chord( int x1, int y1, int x2, int y2, int x3, int y3, int

37、x4, int y4 );BOOL Chord( LPCRECT lpRect, POINT ptStart, POINT ptEnd );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 );图7.7 弦形中心外接矩形弦形(x1,y1)(x2,y2)起点坐标终点坐标图7.8 扇形中心外接矩形扇形(x1,y1)(x2,y2)起点坐标终点坐标7.2.3 图形绘制图形绘制8. Bzier曲线曲线

38、Bzier曲线是最常见的非规则曲线之一,它的形状不仅便于控制,而且更主要的是它具有几何不变性(即它的形状不随坐标的变换而改变),因此在许多场合往往采用这种曲线。Bzier曲线属于三次曲线,只需给定四个点(第一和第四个点是端点,另两个是控制点),就可唯一确定其形状,如图7.9所示。P1P2P3P4图7.9 Bzier曲线8. Bzier曲线曲线函数PolyBezier是用来画出一条或多条Bzier曲线的,其函数原型如下:BOOL PolyBezier( const POINT* lpPoints, int nCount );其中lpPoints是曲线端点和控制点所组成的数组,nCount表示lp

39、Points数组中的点数。如果lpPoints用于画多条Bzier曲线,那么除了第一条曲线要用到四个点之外,后面的曲线只需用三个点,因为后面的曲线总是把前一条曲线的终点作为自己的起始端点。函数PolyBezier不使用也不更新当前位置。如果需要使用当前位置,那么就应该使用PolyBezierTo函数。 BOOL PolyBezierTo( const POINT* lpPoints, int nCount );7.2.3 图形绘制图形绘制9. 绘图示例绘图示例下面来看一个简单的示例。它是用来表示一个班级某门课程的成绩分布,用一个直方图来反映90五个分数段的人数,它需要绘制五个矩形,相邻矩形的填

40、充样式还要有所区别,并且还需要显示各分数段的人数。其结果如图7.10所示。图7.10 Ex_Draw运行结果7.2.3 图形绘制图形绘制例例Ex_Draw 课程的成绩分布直方图课程的成绩分布直方图用MFC AppWizard创建一个默认的单文档应用程序Ex_Draw。为CEx_DrawView类添加一个成员函数DrawScore,用来根据成绩来绘制直方图,该函数的代码如下:void CEx_DrawView:DrawScore(CDC *pDC, float *fScore, int nNum)/ fScore是成绩数组指针,nNum是学生人数int nScoreNum = 0, 0, 0,

41、0, 0;/ 各成绩段的人数的初始值/ 下面是用来统计各分数段的人数for (int i=0; inNum; i+) int nSeg = (int)(fScorei) / 10;/ 取数的十位上的值if (nSeg 6)nSeg = 5;/ 90分数段nScoreNumnSeg - 5 +;/ 各分数段计数int nSegNum = sizeof(nScoreNum)/sizeof(int);/ 计算有多少个分数段 / 求分数段上最大的人数int nNumMax = nScoreNum0;for (i=1; inSegNum; i+) if (nNumMax SelectObject( &b

42、rush1 );/ 将brush1选入设备环境CPen* oldPen = pDC-SelectObject( &pen );/ 将pen选入设备环境CRect rcSeg(rc);rcSeg.right = rcSeg.left + nSegWidth;/ 使每段的矩形宽度等于nSegWidthCString strSeg=90;CRect rcStr;for (i=0; iSelectObject( &brush2 );elsepDC-SelectObject( &brush1 );rcSeg.top = rcSeg.bottom - nScoreNumi*nSegHeight - 2;/

43、 计算每段矩形的高度pDC-Rectangle(rcSeg);if (nScoreNumi 0) CString str;str.Format(%d人, nScoreNumi);pDC-DrawText( str, rcSeg, DT_CENTER | DT_VCENTER | DT_SINGLELINE );rcStr = rcSeg;rcStr.top = rcStr.bottom + 2;rcStr.bottom += 20;pDC-DrawText( strSegi, rcStr, DT_CENTER | DT_VCENTER | DT_SINGLELINE ); / 后面还会讲到rc

44、Seg.OffsetRect( nSegWidth, 0 );/ 右移矩形pDC-SelectObject( oldBrush );/ 恢复原来的画刷属性pDC-SelectObject( oldPen );/ 恢复原来的画笔属性例Ex_Draw(3) 在CEx_DrawView:OnDraw函数中添加下列代码:void CEx_DrawView:OnDraw(CDC* pDC)CEx_DrawDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);float fScore = 66,82,79,74,86,82,67,60,45,44,77,98,65,90

45、,66,76,66, 62,83,84,97,43,67,57,60,60,71,74,60,72,81,69,79,91,69,71,81;DrawScore(pDC, fScore, sizeof(fScore)/sizeof(float);(4) 编译并运行,如前图7.10所示。7.3 字体与文字处理字体与文字处理字体是文字显示和打印的外观形式,它包括了文字的字样、风格和尺寸等多方面的属性。适当地选用不同的字体,可以大大地丰富文字的外在表现力。例如,把文字中某些重要的字句用较粗的字体显示,能够体现出突出、强调的意图。7.3.1 字体和字体对话框字体和字体对话框1. 字体的属性和创建字体的

46、属性和创建字体的属性有很多,但其主要属性有字样、风格和尺寸三个。字样是字符书写和显示时表现出的特定模式,例如,对于汉字,通常有宋体、楷体、仿宋、黑体、隶书以及幼圆等多种字样。字体风格主要表现为字体的粗细和是否倾斜等特点。字体尺寸是用来指定字符所占区域的大小,通常用字符高度来描述。字体尺寸可以取毫米或英寸作为单位,但为了直观起见,也常常采用一种称为“点”的单位,一点约折合为1/72英寸。1. 字体的属性和创建字体的属性和创建逻辑字体的具体属性可由LOGFONT结构来描述,这里仅列最常用到的结构成员。typedef struct tagLOGFONT LONG lfHeight; / 字体的逻辑高

47、度 LONG lfWidth; / 字符的平均逻辑宽度 LONG lfEscapement; / 倾角 LONG lfOrientation; / 书写方向 LONG lfWeight; / 字体的粗细程度 BYTE lfItalic; / 斜体标志 BYTE lfUnderline; / 下划线标志 BYTE lfStrikeOut; / 删除线标志 BYTE lfCharSet; / 字符集,汉字必须为GB2312_CHARSET TCHAR lfFaceNameLF_FACESIZE;/ 字样名称/ LOGFONT; 1. 字体的属性和创建字体的属性和创建根据定义的逻辑字体,用户就可以调

48、用CFont类的CreateFontIndirect函数创建文本输出所需要的字体,如下面的代码:LOGFONT lf;/ 定义逻辑字体的结构变量memset(&lf, 0, sizeof(LOGFONT);/ 将lf中的所有成员置0lf.lfHeight = -13;lf.lfCharSet = GB2312_CHARSET;strcpy(LPSTR)&(lf.lfFaceName), 黑体);/ 用逻辑字体结构创建字体CFontcf;cf.CreateFontIndirect(&lf); / 在设备环境中使用字体CFont* oldfont = pDC-SelectObject(&cf);p

49、DC-TextOut(100,100,Hello);pDC-SelectObject(oldfont);/ 恢复设备环境原来的属性cf.DeleteObject();/ 删除字体对象7.3.1 字体和字体对话框字体和字体对话框2. 使用字体对话框使用字体对话框CFontDialog类提供了字体及其文本颜色选择的通用对话框,如图7.11所示。它的构造函数如下:CFontDialog( LPLOGFONT lplfInitial = NULL, DWORD dwFlags = CF_EFFECTS | CF_SCREENFONTS, CDC* pdcPrinter = NULL, CWnd* pP

50、arentWnd = NULL );其中,参数lplfInitial是一个LOGFONT结构指针,用来设置对话框最初的字体特性。dwFlags指定选择字体的标志。pdcPrinter用来表示打印设备环境指针。pParentWnd表示对话框的父窗口指针。图7.11 字体对话框2. 使用字体对话框使用字体对话框当字体对话框DoModal返回IDOK后,可使用下列的成员函数:void GetCurrentFont( LPLOGFONT lplf );/ 返回用户选择的LOGFONT字体CString GetFaceName( ) const;/ 返回用户选择的字体名称CString GetStyle

51、Name( ) const;/ 返回用户选择的字体样式名称int GetSize( ) const;/ 返回用户选择的字体大小COLORREF GetColor( ) const;/ 返回用户选择的文本颜色int GetWeight( ) const;/ 返回用户选择的字体粗细程度BOOL IsStrikeOut( ) const;/ 判断是否有删除线BOOL IsUnderline( ) const;/ 判断是否有下划线BOOL IsBold( ) const;/ 判断是否是粗体BOOL IsItalic( ) const;/ 判断是否是斜体。2. 使用字体对话框使用字体对话框通过字体对话框

52、可以创建一个字体,如下面的代码:LOGFONT lf;CFontcf;memset(&lf, 0, sizeof(LOGFONT);/ 将lf中的所有成员置0CFontDialog dlg(&lf);if (dlg.DoModal()=IDOK)dlg.GetCurrentFont(&lf);pDC-SetTextColor(dlg.GetColor();cf.CreateFontIndirect(&lf); .7.3.2 常用文本输出函数常用文本输出函数文本的最终输出不仅依赖于文本的字体,而且还跟文本的颜色、对齐方式等有很大关系。CDC类提供了四个输出文本的成员函数:TextOut、ExtT

53、extOut、TabbedTextOut和DrawText。对于这四个函数,用户应根据具体情况来选用。例如,如果想要绘制的文本是一个多列的列表形式,那么采用TabbedTextOut函数,启用制表位,可以使绘制出来的文本效果更佳;如果要在一个矩形区域内绘制多行文本,那么采用DrawText函数,会更富于效率;如果文本和图形结合紧密,字符间隔不等,并要求有背景颜色或矩形裁剪特性,那么ExtTextOut函数将是最好的选择。如果没有什么特殊要求,那使用TextOut函数就显得简练了。下面介绍TextOut、TabbedTextOut和DrawText函数。virtual BOOL TextOut(

54、 int x, int y, LPCTSTR lpszString, int nCount );BOOL TextOut( int x, int y, const CString& str );7.3.2 常用文本输出函数常用文本输出函数virtual CSize TabbedTextOut( int x, int y, LPCTSTR lpszString, int nCount, int nTabPositions, LPINT lpnTabStopPositions, int nTabOrigin );CSize TabbedTextOut( int x, int y, const CS

55、tring& str, int nTabPositions, LPINT lpnTabStopPositions, int nTabOrigin );virtual int DrawText( LPCTSTR lpszString, int nCount, LPRECT lpRect, UINT nFormat );int DrawText( const CString& str, LPRECT lpRect, UINT nFormat );7.3.2 常用文本输出函数常用文本输出函数DrawText函数是当前字体在指定矩形中对文本进行格式化绘制。参数中,lpRect 用来指定文本绘制时的参考

56、矩形,它本身并不显示;nFormat表示文本的格式,它可以是下列的常用值之一或“|”组合:DT_BOTTOM 下对齐文本,该值还必须与DT_SINGLELINE组合DT_CENTER 水平居中DT_END_ELLIPSIS使用省略号取代文本末尾的字符DT_PATH_ELLIPSIS 使用省略号取代文本中间的字符DT_EXPANDTABS 使用制表位,缺省的制表长度为8个字符DT_LEFT 左对齐DT_MODIFYSTRING 将文本调整为能显示的字串DT_NOCLIP 不裁剪DT_NOPREFIX 不支持“&”字符转义DT_RIGHT 右对齐DT_SINGLELINE 指定文本的基准线为参考点

57、DT_TABSTOP 设置停止位。nFormat的高位字节是每个制表位的数目DT_TOP 上对齐DT_VCENTER 垂直居中DT_WORDBREAK 自动换行7.3.2 常用文本输出函数常用文本输出函数例例Ex_DrawText 绘制文本的简单示例绘制文本的简单示例(1) 用MFC AppWizard创建一个默认的单文档应用程序Ex_DrawText。(2) 在CEx_DrawTextView:OnDraw中添加下列代码:void CEx_DrawTextView:OnDraw(CDC* pDC)CEx_DrawTextDoc* pDoc = GetDocument();ASSERT_VAL

58、ID(pDoc);CRect rc(10, 10, 200, 140);pDC-Rectangle( rc );pDC-DrawText( 单行文本居中, rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE);rc.OffsetRect( 200, 0 );/ 将矩形向右偏移200pDC-Rectangle( rc );int nTab = 40;/ 将一个Tab位的值指定为40个逻辑单位pDC-TabbedTextOut( rc.left, rc.top, 绘制tTabt文本t示例, 1, &nTab, rc.left);/ 使用自定义的停止位(Tab)nT

59、ab = 80; / 将一个Tab位的值指定为80个逻辑单位pDC-TabbedTextOut( rc.left, rc.top+20, 绘制tTabt文本t示例, 1, &nTab, rc.left);/ 使用自定义的停止位(Tab)pDC-TabbedTextOut( rc.left, rc.top+40, 绘制tTabt文本t示例, 0, NULL, 0);/ 使用默认的停止位例例Ex_DrawText(3) 编译运行,结果如图7.12所示。图7.12 Ex_DrawText运行结果7.3.3 文本格式化属性文本格式化属性原型如下:virtual COLORREF SetTextColo

60、r( COLORREF crColor );COLORREF GetTextColor( ) const;virtual COLORREF SetBkColor( COLORREF crColor );COLORREF GetBkColor( ) const;int SetBkMode( int nBkMode );int GetBkMode( ) const;其中,nBkMode用来指定文本背景模式,它可以是OPAQUE或TRANSPARENT (透明)。文本对齐方式的设置和获取是由CDC函数SetTextAlign和GetTextAlign决定的。它们的原型如下:UINT SetTextA

61、lign( UINT nFlags );UINT GetTextAlign( ) const;7.3.3 文本格式化属性文本格式化属性上述两个函数中所用到的文本对齐标志如表7.5所示。这些标志可以分为三组:TA_LEFT、TA_CENTER和TA_RIGHT确定水平方向的对齐方式,TA_BASELINE、TA_BOTTOM和TA_TOP确定上下方向的对齐方式,TA_NOUPDATECP和TA_UPDATECP确定当前位置的更新标志。这三组标志中,组与组之间的标志可使用“|”操作符。表表7.5 文本对齐标志文本对齐标志7.3.4 计算字符的几何尺寸计算字符的几何尺寸在打印和显示某段文本时,有必要

62、了解字符的高度计算及字符的测量方式,才能更好地控制文本输出效果。在CDC类中,GetTextMetrics(LPTEXTMETRIC lpMetrics)是用来获得指定映射模式下相关设备环境的字符几何尺寸及其它属性的,其TEXTMETRIC结构描述如下(这里仅列出最常用的结构成员):typedef struct tagTEXTMETRIC / tm int tmHeight; / 字符的高度 (ascent + descent) int tmAscent; / 高于基准线部分的值 int tmDescent;/ 低于基准线部分的值 int tmInternalLeading; / 字符内标高

63、int tmExternalLeading; / 字符外标高 int tmAveCharWidth; / 字体中字符平均宽度 int tmMaxCharWidth; / 字符的最大宽度/ TEXTMETRIC; 7.3.4 计算字符的几何尺寸计算字符的几何尺寸原型如下:CSize GetTextExtent( LPCTSTR lpszString, int nCount ) const;CSize GetTextExtent( const CString& str ) const;CSize GetTabbedTextExtent( LPCTSTR lpszString, int nCount

64、, int nTabPositions, LPINT lpnTabStopPositions ) const;CSize GetTabbedTextExtent( const CString& str, int nTabPositions, LPINT lpnTabStopPositions ) const;其中,参数lpszString和str表示要计算的字符串,nCount表示字符串的字节长度, nTabPositions表示lpnTabStopPositions数组的大小,lpnTabStopPositions表示多个递增的制表位(逻辑坐标)的数组。函数返回当前设备环境下的一行字符串的宽

65、度(CSize的cx)和高度(CSize的cy)。7.3.5 文档内容显示及其字体改变文档内容显示及其字体改变例例Ex_Text 显示文档内容并改变显示的字体显示文档内容并改变显示的字体(1) 用MFC AppWizard创建一个单文档应用程序Ex_Text,在创建的第6步将视图的基类选择为CScrollView。由于视图客户区往往显示不了文档的全部内容,因此需要视图支持滚动操作。(2) 为CEx_TextDoc类添加CStringArray类型的成员变量m_strContents,用来将读取的文档内容保存。(3) 在CEx_TextDoc:Serialize函数中添加读取文档内容的代码:vo

66、id CEx_TextDoc:Serialize(CArchive& ar)if (ar.IsStoring() else CString str;m_strContents.RemoveAll();while (ar.ReadString(str) m_strContents.Add(str);例例Ex_Text(4) 为CEx_TextView类添加LOGFONT类型的成员变量m_lfText,用来保存当前所使用的逻辑字体。(5) 在CEx_TextView类构造函数中添加m_lfText的初始化代码:CEx_TextView:CEx_TextView()memset(&m_lfText,

67、 0, sizeof(LOGFONT);m_lfText.lfHeight = -12;m_lfText.lfCharSet = GB2312_CHARSET;strcpy(m_lfText.lfFaceName, 宋体);例例Ex_Text(6) 用MFC ClassWizard为CEx_TextView类添加WM_LBUTTONDBLCLK(双击鼠标)的消息映射函数,并增加下列代码:void CEx_TextView:OnLButtonDblClk(UINT nFlags, CPoint point) CFontDialog dlg(&m_lfText);if (dlg.DoModal()

68、 = IDOK) dlg.GetCurrentFont(&m_lfText);Invalidate();CScrollView:OnLButtonDblClk(nFlags, point);这样,当双击鼠标左键后,就会弹出字体对话框,从中可改变字体的属性,单击确定按钮后,执行CEx_TextView:OnDraw中的代码。例例Ex_Text(7) 在CEx_TextView:OnDraw中添加下列代码:void CEx_TextView:OnDraw(CDC* pDC)CEx_TextDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);/ 创建字体CFon

69、t cf;cf.CreateFontIndirect(&m_lfText);CFont* oldFont = pDC-SelectObject(&cf);/ 计算每行高度TEXTMETRIC tm;pDC-GetTextMetrics(&tm);int lineHeight = tm.tmHeight + tm.tmExternalLeading;int y = 0;int tab = tm.tmAveCharWidth * 4;/ 为一个TAB设置4个字符 / 输出并计算行的最大长度int lineMaxWidth = 0;CString str;CSize lineSize(0,0);fo

70、r (int i=0; im_strContents.GetSize(); i+) str = pDoc-m_strContents.GetAt(i);pDC-TabbedTextOut(0, y, str, 1, &tab, 0);str = str + A;/ 多计算一个字符宽度lineSize = pDC-GetTabbedTextExtent(str, 1, &tab);if ( lineMaxWidth SelectObject(oldFont);/ 多算一行,以滚动窗口能全部显示文档内容 int nLines = pDoc-m_strContents.GetSize() + 1;C

71、Size sizeTotal;sizeTotal.cx = lineMaxWidth;sizeTotal.cy = lineHeight * nLines;SetScrollSizes(MM_TEXT, sizeTotal);/ 设置滚动逻辑窗口的大小例例Ex_Text(8) 编译运行并测试,打开任意一个文本文件,结果如图7.13所示。图7.13 Ex_Text运行结果7.4 位图、图标与光标位图、图标与光标7.4.1 使用图形编辑器使用图形编辑器在Visual C+ 6.0中,图形编辑器可以创建和编辑任何位图格式的图像资源,除工具栏外,它还用于位图、图标和光标。它的功能很多,如提供一套完整的

72、绘图工具来绘制256色的图形,进行位图的移动和复制以及含有若干个编辑工具等。由于图形编辑器的使用和Windows中的“绘图”工具相似,因此它的具体绘制操作在这里不再重复。这里仅讨论下列一些常用操作。如创建新的图标和光标、选用或定制显示设备和设置光标“热点”等。7.4.1 使用图形编辑器使用图形编辑器1. 创建一个新的图标或光标创建一个新的图标或光标在Visual C+ 6.0中,创建一个应用程序后,当按快捷键Ctrl+R就可打开“插入资源”对话框,从中选择Cursor(光标)或Icon(图标)资源类型,单击新建按钮后,系统为程序添加一个新的图标或光标资源,同时在开发环境右侧出现图形编辑器。图7

73、.14是添加一个新的图标资源后出现的图形编辑器。图7.14 添加图标后的图形编辑器新设备按钮1. 创建一个新的图标或光标创建一个新的图标或光标在创建新图标或光标的时候,图形编辑器首先创建的是一个适合于VGA环境中的图像,开始的时候它以屏幕色(透明方式)来填充。对于创建的新光标,其“热点”被初始化为左上角的点,坐标为(0,0)。默认情况下,图形编辑器所支持的显示设备如表7.6所示。表表7.6 创建图标或光标时可选用的显示设备创建图标或光标时可选用的显示设备7.4.1 使用图形编辑器使用图形编辑器2. 选用和定制显示设备选用和定制显示设备在图形编辑器工作窗口的控制条上,有一个New Device

74、Image按钮,单击此按钮后,系统弹出相应的新设备列表,用户可以从中选取需要的显示设备,如图7.15所示。除了对话框列表框显示的设备外,还可以单击定制按钮,在弹出的对话框中定制新的显示设备,如图7.16所示,在这里可指定新设备的大小和颜色。图7.15 图像设备选择对话框图 图7.16 显示设备的定制 7.4.1 使用图形编辑器使用图形编辑器3. 设置光标热点设置光标热点Windows系统借助光标“热点”来确定光标实际的位置。在图形编辑器的控制条上或光标属性对话框中都可以看到当前的光标“热点”位置。图7.17是添加一个新的光标资源后出现的图形编辑器。控制条设置热点按钮图7.17 添加光标后的图形

75、编辑器7.4.2 位图位图1. CBitmap类类函数原型如下:BOOL LoadBitmap( LPCTSTR lpszResourceName );BOOL LoadBitmap( UINT nIDResource );BOOL CreateBitmap( int nWidth, int nHeight, UINT nPlanes, UINT nBitcount, const void* lpBits );BOOL CreateBitmapIndirect( LPBITMAP lpBitmap );该函数直接用BITMAP结构来创建一个位图对象。BOOL CreateCompatibleB

76、itmap( CDC* pDC, int nWidth, int nHeight );该函数为某设备环境创建一个指定的宽度(nWidth)和高度(nHeight)的位图对象。7.4.2 位图位图2. GDI位图的显示位图的显示由于位图不能直接显示在实际设备中,因此对于GDI位图的显示则必须遵循下列步骤:(1) 调用CBitmap类的CreateBitmap、CreateCompatibleBitmap以及 CreateBitmapIndirect函数创建一个适当的位图对象。(2) 调用CDC:CreateCompatibleDC函数创建一个内存设备环境,以便位图在内存中保存下来,并与指定设备(

77、窗口设备)环境相兼容;(3) 调用CDC:SelectObject函数将位图对象选入内存设备环境中;(4) 调用CDC:BitBlt或CDC:StretchBlt函数将位图复制到实际设备环境中。(5) 使用之后,恢复原来的内存设备环境。2. GDI位图的显示位图的显示例例Ex_BMP 在视图中显示位图在视图中显示位图 (1) 用MFC AppWizard创建一个默认的单文档应用程序Ex_BMP。(2) 按快捷键Ctrl+R,弹出“插入资源”对话框,选择Bitmap资源类型。(3) 单击导入按钮,出现“导入资源”对话框,将文件类型选择为“所有文件(*.*)”,从外部文件中选定一个位图文件,然后单

78、击Import按钮,该位图就被调入应用程序中。保留默认的位图资源标识IDB_BITMAP1。例例Ex_BMP(4) 在CEx_BMPView:OnDraw函数中添加下列代码:void CEx_BMPView:OnDraw(CDC* pDC)CEx_BMPDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);CBitmap m_bmp;m_bmp.LoadBitmap(IDB_BITMAP1);/ 调入位图资源BITMAP bm;/ 定义一个BITMAP结构变量,以便获取位图参数m_bmp.GetObject(sizeof(BITMAP),&bm);CDC d

79、cMem;/ 定义并创建一个内存设备环境dcMem.CreateCompatibleDC(pDC);CBitmap *pOldbmp = dcMem.SelectObject(&m_bmp); / 将位图选入内存设备环境中pDC-BitBlt(0,0,bm.bmWidth,bm.bmHeight,&dcMem,0,0,SRCCOPY);/ 将位图复制到实际的设备环境中dcMem.SelectObject(pOldbmp);/ 恢复原来的内存设备环境例例Ex_BMP(5) 编译运行,结果如图7.18所示。图7.18 Ex_BMP运行结果7.4.3 图标图标1. 图标的调入和清除图标的调入和清除在

80、MFC中,使用CWinApp:LoadIcon函数可将一个图标资源调入并返回一个图标句柄。函数原型如下:HICON LoadIcon( LPCTSTR lpszResourceName ) const;HICON LoadIcon( UINT nIDResource ) const;其中,lpszResourceName和nIDResource分别表示图标资源的字符串名和标识。函数返回的是一个图标句柄。1. 图标的调入和清除图标的调入和清除如果不想创建新的图标资源,也可使用系统中预定义好的标准图标,这时需调用CWinApp:LoadStandardIcon 函数,其原型如下:HICON Loa

81、dStandardIcon( LPCTSTR lpszIconName ) const;其中,lpszIconName可以是下列值之一:IDI_APPLICATION 默认的应用程序图标IDI_HAND 手形图标(用于严重警告)IDI_QUESTION 问号图标(用于提示消息)IDI_EXCLAMATION 警告消息图标(惊叹号)IDI_ASTERISK 消息图标全局函数DestroyIcon可以用来删除一个图标,并释放为图标分配的内存,其原型如下:BOOL DestroyIcon( HICON hIcon );其中,hIcon用来指定要删除的图标句柄。7.4.3 图标图标2. 图标的绘制图标

82、的绘制函数CDC:DrawIcon用来将一个图标绘制在指定的位置处,其原型如下:BOOL DrawIcon( int x, int y, HICON hIcon );BOOL DrawIcon( POINT point, HICON hIcon );其中,(x, y)和point用来指定图标绘制的位置,而hIcon用来指定要绘制的图标句柄。7.4.3 图标图标3. 应用程序图标的改变应用程序图标的改变在用MFC AppWizard创建的应用程序中,图标资源IDR_MAINFRAME用来表示应用程序窗口的图标,通过图形编辑器可将其内容直接修改。实际上,程序中还可使用GetClassLong和Se

83、tClassLong函数重新指定应用程序窗口的图标,函数原型如下:DWORD SetClassLong( HWND hWnd, int nIndex, LONG dwNewLong);DWORD GetClassLong( HWND hWnd, int nIndex);其中,hWnd用来指定窗口类句柄,dwNewLong 用来指定新的32位值。nIndex用来指定与WNDCLASSEX结构相关的索引,它可以是下列值之一:GCL_HBRBACKGROUND 窗口类的背景画刷句柄GCL_HCURSOR 窗口类的的光标句柄GCL_HICON窗口类的的图标句柄GCL_MENUNAME 窗口类的的菜单资

84、源名称7.4.3 图标图标4. 示例示例(1) 用MFC AppWizard创建一个默认的单文档应用程序Ex_Icon。(2) 新添四个图标资源,通过图像设备选择对话框(参见图7.15),选择Small(16 16)作为图标的设备类型。图标资源ID号分别为默认的IDI_ICON1 IDI_ICON4。(3) 用图形编辑器绘制图标,结果如图7.19所示。图7.19 创建的四个图标4. 示例示例(4) 为CMainFrame类添加一个成员函数ChangeIcon,用来切换应用程序的图标。该函数的代码如下:void CMainFrame:ChangeIcon(UINT nIconID)HICON h

85、IconNew = AfxGetApp()-LoadIcon(nIconID);HICON hIconOld = (HICON)GetClassLong(m_hWnd, GCL_HICON);if (hIconNew != hIconOld) DestroyIcon(hIconOld);SetClassLong(m_hWnd, GCL_HICON, (long)hIconNew);RedrawWindow();/ 重绘窗口4. 示例示例(5) 在CMainFrame:OnCreate函数的最后添加计时器设置代码:int CMainFrame:OnCreate(LPCREATESTRUCT lp

86、CreateStruct)if (CFrameWnd:OnCreate(lpCreateStruct) = -1)return -1;.SetTimer(1, 500, NULL);return 0;4. 示例示例(6) 用MFC ClassWizard为CMainFrame类添加WM_TIMER的消息映射函数,并增加下列代码:void CMainFrame:OnTimer(UINT nIDEvent) static int icons = IDI_ICON1, IDI_ICON2, IDI_ICON3, IDI_ICON4;static int index = 0;ChangeIcon(ic

87、onsindex);index+;if (index3) index = 0;CFrameWnd:OnTimer(nIDEvent);OnTimer函数的参数nIDEvent用来表示发送WM_TIMER消息的计时器的标识值。4. 示例示例(7) 用MFC ClassWizard为CMainFrame类添加WM_DESTROY的消息映射函数,并增加下列代码:void CMainFrame:OnDestroy() CFrameWnd:OnDestroy();KillTimer(1);代码中,KillTimer函数是CWnd类成员函数,用来停止WM_TIMER消息的传送,其函数参数值用指定要停用的计

88、时器标识值。(8) 编译并运行。可以看到任务栏上的按钮以及应用程序的标题栏上四个图标循环显示的动态效果,显示速度为每秒两帧。7.4.4 光标光标光标在Windows程序中起着非常重要的作用,它不仅能反映鼠标的运动位置,而且还可以表示程序执行的状态,引导用户的操作,使程序更加生动。例如沙漏光标表示“正在执行,请等待”,IE中手形光标表示“可以跳转”,另外还有一些有趣的动画光标。光标又称为“鼠标指针”。1. 使用系统光标使用系统光标Windows预定义了一些经常使用的标准光标,这些光标均可以使用函数CWinApp: LoadStandardCursor加载到程序中,其函数原型如下:HCURSOR

89、LoadStandardCursor( LPCTSTR lpszCursorName ) const;其中,lpszCursorName用来指定一个标准光标名,它可以是下列宏定义:IDC_ARROW 标准箭头光标 IDC_IBEAM 标准文本输入光标IDC_WAIT 漏斗型计时等待光标 IDC_CROSS 十字形光标IDC_UPARROW 垂直箭头光标 IDC_SIZEALL 四向箭头光标IDC_SIZENWSE 向下的双向箭头光标 IDC_SIZENESW 向上双向箭头光标IDC_SIZEWE 左右双向箭头光标 IDC_SIZENS 上下双向箭头光标例如,加载一个垂直箭头光标IDC_UPAR

90、ROW的代码如下:HCURSOR hCursor;hCursor = AfxGetApp()-LoadStandardCursor(IDC_UPARROW);7.4.4 光标光标2. 使用光标资源使用光标资源用编辑器创建或从外部调入的光标资源,可通过函数CWinApp:LoadCursor进行加载,其原型如下:HCURSOR LoadCursor( LPCTSTR lpszResourceName ) const;HCURSOR LoadCursor( UINT nIDResource ) const;其中,lpszResourceName和nIDResource分别用来指定光标资源的名称或I

91、D号。例如,当光标资源为IDC_CURSOR1时,则可使用下列代码:HCURSOR hCursor;hCursor = AfxGetApp()-LoadCursor(IDC_CURSOR1);7.4.4 光标光标3. 更改程序中的光标更改程序中的光标更改应用程序中的光标除了可以使用GetClassLong和SetClassLong函数外,最简单的方法是用MFC ClassWizard映射WM_SETCURSOR消息,该消息是当光标移动到一个窗口内并且还没有捕捉到鼠标时产生的。CWnd为此消息的映射函数定义这样的原型:afx_msg BOOL OnSetCursor( CWnd* pWnd, U

92、INT nHitTest, UINT message );其中,pWnd表示拥有光标的窗口指针,nHitTest用来表示光标所处的位置,例如当为HTCLIENT时表示光标在窗口的客户区中,而为HTCAPTION 时表示光标在窗口的标题栏处,为HTMENU时表示光标在窗口的菜单栏区域等等。message用来表示鼠标消息。在OnSetCursor函数调用SetCursor来设置相应的光标,并将OnSetCursor函数返回TRUE,就可改变当前的光标了。7.4.4 光标光标4. 示例示例本示例用来根据当前鼠标所在的位置来确定单文档应用程序光标的类型,当处在标题栏时为一个动画光标,当处在客户区时为一

93、个自定义光标。例例Ex_Cursor 改变应用程序光标改变应用程序光标(1) 用MFC AppWizard创建一个默认的单文档应用程序Ex_Cursor。(2) 按快捷键Ctrl+R,打开“插入资源”对话框,选择“Cursor”类型后,单击新建按钮。(3) 在图形编辑器工作窗口的控制条上,单击“New Device Image”按钮,从弹出的“New Device Image”对话框中,单击定制按钮。(4) 在弹出的“定制图像”对话框中,保留默认的大小和颜色数,单击确定按钮。回到“New Device Image”对话框。(5) 选择“32 x 32, 16 colors”设备类型,单击确定按

94、钮。(6) 在图形编辑器的“Device”组合框中,选择“Monochrome 32 x 32 ”,打开系统Image菜单,选择“Delete Device Image”命令,删除“Monochrome 32 x 32 ”设备类型。如果不这样做,加载后的光标不会采用“32 x 32, 16 colors”设备类型。例例Ex_Cursor(7) 保留默认的ID号IDC_CURSOR1,用图形编辑器绘制光标图形,指定光标热点位置为(15, 15),结果如图7.20所示。(8) 为CMainFrame类添加一个成员变量m_hCursor,变量类型为光标句柄HCURSOR。图7.20 创建的光标例例E

95、x_Cursor(9) 用MFC ClassWizard为CMainFrame类添加WM_SETCURSOR的消息映射函数,并增加下列代码:BOOL CMainFrame:OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) BOOL bRes = CFrameWnd:OnSetCursor(pWnd, nHitTest, message);if (nHitTest = HTCAPTION ) m_hCursor = LoadCursorFromFile(c:windowscursorsglobe.ani);SetCursor(m_hCursor);bRes = TRUE;else if (nHitTest = HTCLIENT ) m_hCursor = AfxGetApp()-LoadCursor(IDC_CURSOR1);SetCursor(m_hCursor);bRes = TRUE;return bRes;例例Ex_Cursor (10) 编译运行并测试。当鼠标移动到标题栏时,光标变成了globe.ani的动画光标,而当移动到客户区时,光标变成了IDC_CURSOR1定义的形状。

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 资格认证/考试 > 自考

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号