Visual-C++基础教程-[132页]课件

PPT
  • 阅读 71 次
  • 下载 0 次
  • 页数 132 页
  • 大小 1.971 MB
  • 2022-11-24 上传
  • 收藏
  • 违规举报
  • © 版权认领
下载文档40.00 元 加入VIP免费下载
此文档由【小橙橙】提供上传,收益归文档提供者,本网站只提供存储服务。若此文档侵犯了您的版权,欢迎进行违规举报版权认领
Visual-C++基础教程-[132页]课件
可在后台配置第一页与第二页中间广告代码
Visual-C++基础教程-[132页]课件
可在后台配置第二页与第三页中间广告代码
Visual-C++基础教程-[132页]课件
可在后台配置第三页与第四页中间广告代码
Visual-C++基础教程-[132页]课件
Visual-C++基础教程-[132页]课件
还剩10页未读,继续阅读
【这是免费文档,您可以免费阅读】
/ 132
  • 收藏
  • 违规举报
  • © 版权认领
下载文档40.00 元 加入VIP免费下载
文本内容

【文档说明】Visual-C++基础教程-[132页]课件.ppt,共(132)页,1.971 MB,由小橙橙上传

转载请保留链接:https://www.ichengzhen.cn/view-44713.html

以下为本文档部分文字说明:

第10章图形输出第10章图形输出10.1图形设备接口10.2画笔和画刷10.3绘图10.4文本和字体习题第10章图形输出10.1.1设备环境当Windows应用程序在屏幕、打印机或其它输出设备上画图时,它并不是将像素直接输出到设备上,而是将图形绘制到由设备环境(Dev

iceContext,DC)表示的逻辑显示平面上。设备环境是Windows定义和管理的一个数据结构,它包含了GDI需要的、与逻辑显示平面相关的所有绘图属性,如当前的画笔、画刷、字体和位图等图形对象及其属性,以及颜色、

背景和绘图模式,这些属性决定了最后输出的效果。可以将设备环境看做是一个绘图工具箱,它包括画布及各种各样的绘图工具。在绘图之前,可以改变设备环境的属性,例如可以选择不同颜色、大小的字体,设置画笔的粗细和颜色。10.1图形设备接口第10章图形输出在绘图之前,应用程序必须从GDI获取设备环境的句柄,

并将其传递给GDI绘图函数。若无有效的设备环境句柄,则GDI不会输出任何内容。采用传统的调用API编程方式,在响应消息WM_PAINT的处理函数中调用API函数BeginPaint,以获取设备环境句柄,使用结束后调用EndPa

int释放设备环境。在其它函数中绘图,需要调用GetDC获取设备环境,调用ReleaseDC释放设备环境。MFC的CDC类将Windows设备环境和获取设备环境句柄的GDI函数封装在一起,因此,在使用MFC编写Windows应用程序

时,不必直接获取设备环境句柄,而是通过创建一个设备环境对象并调用它的成员函数来画图。CDC的派生类如CPaintDC、CClientDC和CWindowDC则代表Windows应用程序使用的不同类型的设备环境。MFC提供的CDC派生类如表10-1所示。第10章图形输出表1

0-1CDC的派生类类名描述CPaintDC用于在窗口客户区域绘图(仅限于OnPaint处理函数)CClientDC用于在窗口客户区域绘图(除OnPaint外的任何处理程序)CWindowDC用于在窗口类任意地

方绘图,包括非客户区域CMetaFileDC用于向GDI元文件绘图第10章图形输出除了CMetaFileDC外,这些类的构造函数和析构函数均调用相应的函数获取和释放设备环境,从而使得设备环境的使用非常方便。若在栈上定义设备环境

对象,当对象的作用域结束时,则其析构函数会被自动调用,释放设备环境。如:CClientDCdc(this);//利用dc绘图若使用new动态创建设备环境对象,如:CClientDC*pDC=newCClientDC(this);则在设备环境使用结束时必须使用delet

e删除对象:deletepDC;以便调用析构函数释放设备环境。第10章图形输出由于设备环境是Windows操作系统中的资源,因此要确保应用程序使用完设备环境后及时释放。否则,会由于系统中资源数目的限制而影响其它应用程序的运行。CPa

intDC类代表了一个窗口的绘图画面,允许在窗口的客户区域画图。但CPaintDC只能在消息WM_PAINT的处理函数OnPaint中使用,而不能在其它地方使用。CClientDC类代表一个窗口客户区设备

环境,窗口的客户区是指窗口中不包括边框、标题栏、菜单栏、工具栏和状态栏的区域。坐标点(0,0)通常指客户区的左上角。如果需要在整个窗口区域绘图,则应使用CWindowDC类,它代表了整个窗口设备环境,包括窗口边框、标题

栏、菜单栏、工具栏和状态栏等非客户区和客户区。坐标点(0,0)通常指窗口的左上角。在MFC应用程序中,视图窗口没有非客户区,因此,CWindowDC更适用于框架窗口。有时可以使用CWindowDC创建特殊效果,例如用户自己绘制标题栏和带圆角的窗口。第10章图形输出【例10.1】CPai

ntDC、CClientDC和CWindowDC的使用示例。程序的创建过程如下:(1)利用AppWizard创建一个单文档界面应用程序,项目名设置为EX10_1。(2)利用ClassWizard在视图类CEX10_1View中添加消

息WM_PAINT的处理函数OnPaint,并添加如下黑体所示的代码:voidCEX10_1View::OnPaint(){CPaintDCdc(this);//devicecontextforpaintingCRectrect;GetClientRect(&rect

);dc.Ellipse(rect);}第10章图形输出(3)利用ClassWizard在视图类CEX10_1View中添加消息WM_LBUTTONDOWN的处理函数OnLButtonDown,并添加如下黑体所示的代码:voidCEX10_1View::

OnLButtonDown(UINTnFlags,CPointpoint){CClientDCdc(this);dc.LineTo(100,100);dc.TextOut(100,100,"在视图窗口客户区绘图");}第10章图形输出(4)利用菜单编辑器添加菜单命令“在框架

窗口绘图”(菜单编辑器的使用见第11章),取消其Pop-up属性,设置其ID为IDM_DRAW。利用ClassWizard在框架窗口类CMainFrame中添加此菜单的COMMAND消息处理函数OnDraw,并添加如下黑体所示的代码:voidCMainFrame::OnDraw(){C

WindowDCdc(this);CPenpen(PS_SOLID,4,RGB(255,0,0));dc.SelectObject(&pen);dc.LineTo(100,100);dc.TextOu

t(100,100,"在框架窗口内绘图");}第10章图形输出(5)编译、链接和运行程序。当在视图窗口中单击鼠标左键和执行菜单命令“在框架窗口绘图”后,结果如图10-1所示。图10-1例10-1程序运行结果第10章图形输出10.1.2设备环境的属性获取图形设备接口的

设备环境后,就可以在设备环境上绘图,但当使用CDC的输出函数绘图时,在屏幕上(或打印机等其它设备)上所看到的某些输出特性依赖于设备环境当前的属性。例如,当使用TextOut输出文字时,可以在函数中指定输出的坐标位置和要输出的字符串,但没有规定文本颜色和字体及字体的

大小,这些由设备环境当前的属性来决定。因此,当获取GDI设备环境后,还需要设置设备环境的属性。第10章图形输出设备环境的属性包括以下内容:·相关的GDI对象,如画笔(Pen)、画刷(Brush)、字体(Fo

nt)、位图(Bitmap)、调色板(Palette)和区域(Region)。·决定绘图时缩放尺寸的映射模式和绘图模式。·其它各种细节,例如文本颜色、背景颜色等。当创建一个设备环境对象时,它有一些默认的属性,例如,输出文本时有默认的字体及大小、颜色等。当需要输出其它特

性时,在绘图之前需要通过CDC类的成员函数进行相应的属性设置。表10-2列出了设备环境中常用的一些属性和访问与设置这些属性的CDC类成员函数。第10章图形输出表10-2常用的设备环境属性及其相关函数属性默认值设置获取文本颜色BLACKSetTextColorGetTextColor背景颜色

WHITESetBkColorGetBkColor背景模式OPAQUESetBkModeGetBkMode映射模式MM_TEXTSetMapModeGetMapMode绘图模式R2_COPYPENSetROP2GetROP2当前位置(0,0)MoveToGetCurrentPos

ition当前画笔BLACK_PENSelectObjectSelectObject当前画刷WHITE_BRUSHSelectObjectSelectObject当前字体SYSTEM_FONTSelectObjectSelectObject第10章图形输出不同的CDC输出函数以不同的方式使

用设备环境的属性。例如,在使用Rectangle函数画矩形时,GDI用当前的画笔画矩形区域的边界,并用当前的画刷填充该矩形区域。所有的文本输出函数都采用当前的字体,文本颜色和背景颜色决定了在文本输出时所有用到的颜色。文本颜色决定了字符的颜色,而背景颜色决定字符后面的填充色。在使用L

ineTo函数画虚线或点划线时,背景颜色还用于填充线段间的空隙,或用来填充阴影画笔所画标记间的空白处。如果想忽略背景颜色,可将背景模式设置为透明(TRANSPARENT),例如:dc.SetBkMode(TRANSPARENT);第10章图形输出MFC提

供6个GDI对象类用于改变设备环境的相应属性,它们是CBitmap、CBrush、CFont、CPalette、CPen和CRgn,它们分别代表位图、画刷、字体、调色板、画笔和区域。这些类的继承关系如图10-2所示。在应用程序中可以创建这些GDI对象,然后通过调用CDC::

SelectObject成员函数将创建的GDI对象选入设备环境,从而改变设备环境的属性。除非调用SelectObject或SelectStockObject改变当前画笔、画刷或字体,否则,GDI将使用设备环境的默认值。例如,要绘制一个红色的圆,并使其具有10个像素宽的黑色

边框,则要创建一个10个像素点宽的黑色画笔和一个红色的画刷,并在调用CDC::Ellipse画圆之前用SelectObject将它们选入设备环境。第10章图形输出CObjectCGdiObjectCBrushCFontC

BitmapCPaletteCPenCRgn图10-2GDI对象类的继承关系第10章图形输出例如将例10.1视图类中响应消息WM_LBUTTONDOWN的处理函数OnLButtonDown修改为如下形式,则

在窗口客户区单击鼠标时可绘制一个10像素宽的黑色边框的红色圆:voidCEX10_1View::OnLButtonDown(UINTnFlags,CPointpoint){//TODO:Addyourmessagehandlercodehereand/orcalldefaultCCli

entDCdc(this);CPenpen(PS_SOLID,10,RGB(0,0,0));//创建10像素宽的黑色画笔dc.SelectObject(&pen);//将画笔选入设备环境CBrushbrush(RGB(255,0,0));//创建红色的画刷dc.SelectOb

ject(&brush);dc.Ellipse(0,0,100,100);}第10章图形输出除了可以自定义GDI对象并选入设备环境来改变设备环境的属性外,Windows预先定义了一些画笔、画刷、字体以及其

它一些GDI对象,这些对象是Windows的一部分,可以直接使用。通过调用CDC::SelectStockObject成员函数将库存GDI对象选入设备环境,其函数原型为:virtualCGdiObject*SelectStockO

bject(intnIndex);函数返回指向设备环境以前的GDI对象的指针。参数“nIndex”指定要选入设备环境的库存对象。表10-3列出了可以选入设备环境的画笔和画刷库存对象。第10章图形输出表10-3Windows库存

的画笔和画刷nIndex参数描述BLACK_BRUSH黑色画刷DKGRAY_BRUSH深灰色画刷GRAY_BRUSH灰色画刷HOLLOW_BRUSH与NULL_BRUSH相同LTGRAY_BRUSH浅灰色画刷NULL_BRUSH空画刷(内部

不填充)WHITE_BRUSH白色画刷BLACK_PEN黑色画笔NULL_PEN空画笔(不画)WHITE_PEN白色画笔第10章图形输出10.1.3绘图模式当向GDI设备环境的逻辑显示面输出图形时,GDI并不是简单地输出图形像素点的颜色,而是将输出图形画笔颜色和图

形内部的填充色与显示平面目标位置上的颜色进行某种逻辑运算,然后将运算的结果颜色输出。设备环境的绘图模式属性决定了当前设备环境的逻辑运算。绘图模式使用CDC::SetROP2成员函数进行设置,其函数原型为:

intSetROP2(intnDrawMode);其中:参数“nDrawMode”用来指定新的绘图模式。表10-4列出了一些常用的绘图模式。函数返回设备环境先前的绘图模式。设备环境默认的绘图模式是R2_COPY

PEN。第10章图形输出表10-4设备环境的绘图模式绘图模式(nDrawMode)执行的运算R2_BLACK最后像素总是黑色R2_WHITE最后像素总是白色R2_NOP屏幕像素颜色保持不变(最后像素=屏幕像素)R2_NOT屏幕颜色的反色(最后像素=NOT屏幕

像素)R2_COPYPEN画笔的颜色(最后像素=画笔)R2_NOTCOPYPEN画笔颜色的反色(最后像素=NOT画笔)R2_MERGEPENNOT最后像素=(NOT屏幕像素)OR画笔R2_MASKPE

NNOT最后像素=(NOT屏幕像素)AND画笔R2_MERGENOTPEN最后像素=(NOT画笔)OR屏幕像素R2_MASKNOTPEN最后像素=(NOT画笔)AND屏幕像素R2_MERGEPEN最后像素=画笔OR屏幕像素R2_MASKPEN最后像素=画笔AND屏幕像素R2_XORPEN最

后像素=画笔XOR屏幕像素R2_NOTXORPEN最后像素=NOT(画笔XOR屏幕像素)第10章图形输出表中的“画笔”指输出图形画笔颜色和图形内部的填充色。绘图模式有时非常有用,例如在游戏设计中,如果想恢复游戏背景,只需要将绘图模式设置为R2_XORPEN

,然后再次输出前景图像即可。【例10.2】绘图模式使用示例。设计一个单文档界面应用程序,项目名为EX10_2。利用ClassWizard在视图类CEX10_2View中添加消息WM_LBUTTONDOWN的处理函数OnLButton

Down,并添加如下黑体所示的代码:第10章图形输出voidCEX10_2View::OnLButtonDown(UINTnFlags,CPointpoint){//TODO:Addyourmessagehandlercodeh

ereand/orcalldefaultCClientDCdc(this);CRectrect(10,10,60,160);dc.SelectStockObject(BLACK_BRUSH);dc.Rectangle(rect);rect.OffsetRect(50,0);dc.

SelectStockObject(WHITE_BRUSH);dc.Rectangle(rect);rect.OffsetRect(50,0);dc.SelectStockObject(BLACK_BRUSH);dc.Rectangle(rect);dc.Sele

ctStockObject(NULL_BRUSH);dc.SetROP2(R2_NOT);dc.Ellipse(10,10,160,160);}第10章图形输出运行程序时,在视图窗口单击鼠标左键,则结果如图10-3所示。图

10-3绘图模式的使用示例第10章图形输出10.1.4映射模式与坐标转换1.坐标系统当在应用程序中输出图形或文本时,需要指定图形或文本绘制的位置,这时指定的坐标位置是参照某个坐标系统的。在Windows中,坐标系统大致可以分为两大类:设备坐标系统和逻辑坐标系统。设备坐标系统是指显

示器或打印机等物理设备的坐标系统。不同的物理设备具有不同的坐标单位、坐标原点和坐标方向,对于显示设备,坐标单位为像素,设备上的(0,0)始终在显示平面的左上角,X轴正向向右,Y轴正向向下。第10章图形输出在设备坐标系统中又有三种相互独立的坐标系统:屏幕坐标系统、窗口坐标系统和用户区

坐标系统。这些坐标系统均以像素点来表示度量的单位,X轴向右为正,Y轴向下为正。屏幕坐标系统使用整个屏幕坐标区作为坐标系统。窗口坐标系统使用包括边框在内的应用程序的窗口作为坐标区域,窗口的左上角为坐标原

点。用户区坐标系统是最经常使用的坐标系统,以窗口的客户区域作为坐标区域。调用CWnd::ClientToScreen和CWnd::ScreenToClient函数可实现用户区坐标值与屏幕坐标值之间的转换。当调用一个返回屏幕坐标值的

Windows函数,并需要将返回的屏幕坐标值再传递给需要用户区坐标值的函数(或者反过来)时,就需要使用上面两个函数。第10章图形输出逻辑坐标系统是与GDI设备环境相关的坐标系统,这种坐标不考虑具体的物理设备。例如,当应用程序绘制一条从A点到

B点的直线时,传递给MoveTo()和LineTo()函数的坐标不是指定屏幕上的物理位置,而是其在设备环境中定义的逻辑坐标系统中的坐标。当使用CDC成员函数在某个设备环境中绘图时,图形输出到一个逻辑窗口,GDI需要将在逻辑窗口中的逻辑坐标转换为设备坐标才能将图形在显示器或打印机上

输出。从逻辑坐标值到设备坐标值的转换方式,由设备环境的映射模式属性决定。第10章图形输出2.映射模式映射模式是设备环境的属性,用于确定从逻辑坐标到设备坐标的转换方式。在绘图时,Windows根据当前设备环境的映射模式将逻辑坐标转换为设备坐标。映射模式定义了逻辑单位的实际大小、坐标增长方向

,所有映射模式的坐标原点一般在图形输出区域的左上角。Windows支持8种不同的映射模式,如表10-5所示。第10章图形输出表10-5Windows映射模式映射模式逻辑单位坐标轴方向MM_TEXT一个像素X轴正向向右,Y轴正向向下MM_LOMETRIC0.1毫米X轴正向向右,Y轴正向

向上MM_HIMETRIC0.01毫米X轴正向向右,Y轴正向向上MM_LOENGLISH0.01英寸X轴正向向右,Y轴正向向上MM_HIENGLISH0.001英寸X轴正向向右,Y轴正向向上MM_TWIPS1/

1440英寸X轴正向向右,Y轴正向向上MM_ISOTROPIC用户自定义,X轴与Y轴的单位比例为1:1用户自定义MM_ANISOTROPIC用户自定义,X轴与Y轴的单位比例可以任意用户自定义第10章图形输出映射模式的坐标原点一般在图形输出区域的左上角,在使用MM_LOMETRIC

、MM_HIMETRIC、MM_LOENGLISH、MM_HIENGLISH和MM_TWIPS时,由于它们的Y轴都为正向向上,为了使输出可见,Y坐标必须使用负值。例如:dc.Rectangle(0,0,200,-100);因此,在使用非MM_TEXT映射模式时

,如果应用程序的输出不可见,应检查Y坐标值的正负号。设备环境默认的映射模式为MM_TEXT。如果需要使用其它的映射模式,可以调用CDC::SetMapMode成员函数来设置新的映射模式。使用CDC::GetMapMode成员函数可以获取当前的映射模式。例如

,以下语句将映射模式设置为MM_LOMETRIC,并画一个半径为2.5厘米的圆:dc.SetMapMode(MM_LOMETRIC);dc.Ellipse(0,0,500,-500);第10章图形输出除了6种固定比例的映射模

式外,Windows还提供了两种可变比例的映射模式:MM_ISOTROPIC和MM_ANISOTROPIC,允许用户改变比例因子和原点,即用户自己决定从逻辑坐标转换为设备坐标的方式。MM_ISOTROPIC和MM_ANISOTROPIC映射模式常用于

根据窗口尺寸按比例自动调整图形输出的大小,在用户改变窗口的大小时,输出的内容也会改变大小。例如,下面是一个单文档应用程序的OnDraw函数,它首先使用MM_ANISOTROPIC映射模式将窗口客户区大小(无论其为多大)映射为逻辑坐标的500单位宽和500单位长

,坐标原点位于窗口左上角,X轴正向向右,Y轴正向向下;然后画一个与窗口边框相接的椭圆。当用户改变窗口大小时,椭圆始终占据整个窗口。第10章图形输出voidCEX10_2View::OnDraw(CDC*pDC

){CRectclientRect;GetClientRect(clientRect);pDC->SetMapMode(MM_ANISOTROPIC);pDC->SetWindowExt(500,500);pDC->SetViewportExt(clientRect

.Width(),clientRect.Height());pDC->Ellipse(0,0,500,500);}如果希望Y轴正向向上,则只需要将传递给SetWindowExt或SetViewportExt

的Y坐标值取反即可。第10章图形输出CDC::SetWindowExt函数以逻辑尺寸设置“窗口范围”,其函数原型为:virtualCSizeSetWindowExt(intcx,intcy);virtualCSizeSetWindowExt(SIZEsize);其中,参数“cx”和“cy”或“si

ze”以逻辑单位指定窗口大小。CDC::SetViewportExt函数以设备单位或像素点设置“视口范围”,其函数原型为:virtualCSizeSetViewportExt(intcx,intcy);virtualCSizeSetViewportExt(SIZEsize);第10

章图形输出Windows对逻辑坐标值和设备坐标值的相互转换,是根据用户指定的窗口逻辑尺寸(窗口范围)、实际尺寸(视口范围)以及坐标原点位置进行的。设定窗口范围和视口范围时,实际上是在自己确定缩放比例。一般说来

,视口范围是画图所在窗口的大小(以像素点数目计算),而窗口范围是指以逻辑单位表示的窗口尺寸。MM_ISOTROPIC和MM_ANISOTROPIC映射模式的区别在于前者始终保持1:1的纵横比,后者X和Y比例因子可以分别改变。使用SetWindowExt和SetViewp

ortExt时要注意:在MM_ISOTROPIC映射模式下,应该首先调用SetWindowExt。而在MM_ANISOTROPIC映射模式下,窗口范围和视口范围中先设置哪个都无关紧要。第10章图形输出3.坐标原点在各种映射模式下,设备环境的

原点默认位于显示平面的左上角。用户可以改变坐标原点的位置。MFC的CDC类提供了两个函数用于移动坐标原点。CDC::SetWindowOrg用于移动窗口原点,CDC::SetViewportOrg用于移动视口原点,一般情况下,只

能使用其中之一。SetViewportOrg的参数为设备坐标值,SetViewportOrg(x,y)将视口原点移至(x,y),即通知Windows将逻辑原点(0,0)映射成设备点(x,y)。SetWindowOrg的参数为逻辑坐标值,SetWindowOrg(x,y)将窗口原点移至(x,y),即

通知Windows将逻辑点(x,y)映射成设备原点(0,0),即显示平面左上角。第10章图形输出【例10.3】移动原点示例。创建一单文档界面应用程序,项目名为EX10_3。在视图类CEX10_3View的OnDraw函数中添加如下代码:void

CEX10_3View::OnDraw(CDC*pDC){CRectclientRect;GetClientRect(clientRect);pDC->SetMapMode(MM_LOMETRIC);pDC->SetViewportOrg(

clientRect.Width()/2,clientRect.Height()/2);pDC->Ellipse(-250,250,250,-250);}程序首先设置映射模式为MM_LOMETRIC,然后将逻辑原点移至窗口客户区中心,再在窗口客

户区中绘制一半径为2.5厘米的圆,如图10-4所示。第10章图形输出图10-4例10.3运行结果第10章图形输出4.坐标转换当设置好设备环境的映射模式及逻辑平面原点后,便可以调用CDC成员函数绘图,大多数CDC成员函数使用逻

辑坐标作为参数。但Windows应用程序不能只在逻辑坐标下工作,经常还涉及到设备坐标,例如鼠标单击消息处理函数OnLButtonDown中的point参数表示单击时鼠标的坐标,是设备坐标。许多MFC成员函数使用设备坐标作为参数,例如CWnd成员函数、CRect的成员函数等都是

用设备坐标作为参数。因此,应用程序经常需要在设备坐标和逻辑坐标之间进行切换。第10章图形输出调用CDC::LPtoDP函数可将逻辑坐标值转换为设备坐标值,函数原型为:voidLPtoDP(LPPOINTlpPoints,intnCount=

1)const;voidLPtoDP(LPRECTlpRect)const;voidLPtoDP(LPSIZElpSize)const;其中,参数“lpPoints”为指向由点构成的数组,数组中的每一个点是一个POINT结构变量或CPoint对象;“nCount”为数组中点的数目;“l

pRect”为指向RECT结构变量或CRect对象的指针,常用于将一个矩形从逻辑坐标转换为设备坐标;“lpSize”为指向SIZE结构变量或CSize对象的指针。第10章图形输出调用CDC::DPtoLP函数可将设备坐标值

转换为逻辑坐标值,函数原型为:voidDPtoLP(LPPOINTlpPoints,intnCount=1)const;voidDPtoLP(LPRECTlpRect)const;voidDPtoLP(LPSIZElpSize)const;在响应鼠标单击的命中

测试调用CRect::PtInRect或CRgn::PtInRegion时,设备坐标和逻辑坐标之间的转换是必不可少的。鼠标单击后得到的鼠标指针位置坐标是设备坐标值,如果在某个设备环境中画了一个圆并且想知道鼠标单

击是否发生在这个圆内,则需要将圆的逻辑坐标值转换为设备坐标值,或将鼠标单击获得的设备坐标值转换为逻辑坐标值。否则就是在比较两个不同种类的坐标,不能保证测试结果的正确性。第10章图形输出【例10.4】编写一个单文档界面应用程序,通过用鼠标单击客户区域的圆来改变圆的颜色。程

序的创建过程如下:(1)利用AppWizard创建一单文档界面应用程序,项目名为EX10_4。(2)在视图类CEX10_4View类的头文件EX10_4View.h中添加数据成员:private:intm

_nColor;//画圆时画刷的颜色CRectm_rectEllipse;//圆的外接矩形在视图类的构造函数中对添加的数据成员进行初始化:CEX10_4View::CEX10_4View():m_re

ctEllipse(0,0,200,-200){m_nColor=GRAY_BRUSH;}第10章图形输出(3)在视图类的OnDraw成员函数中设置画刷颜色及映射模式,并用外接矩形画圆:voidCEX10_4View:

:OnDraw(CDC*pDC){pDC->SelectStockObject(m_nColor);pDC->SetMapMode(MM_LOMETRIC);pDC->Ellipse(m_rectEllipse);}(4)利用ClassWi

zard在视图类CEX10_4View中添加消息WM_LBUTTONDOWN的处理函数OnLButtonDown,并添加如下黑体代码:第10章图形输出voidCEX10_4View::OnLButtonDown(UINTnFlags,CP

ointpoint){CClientDCdc(this);dc.SetMapMode(MM_LOMETRIC);CRectrectDevice=m_rectEllipse;dc.LPtoDP(&rectDevice);//

将外接矩形转换为设备坐标值if(rectDevice.PtInRect(point))//测试鼠标单击是否在圆的外接矩形内{if(m_nColor==GRAY_BRUSH)m_nColor=WHITE_BRUSH;elsem

_nColor=GRAY_BRUSH;InvalidateRect(rectDevice);//使矩形无效,更新视图}}第10章图形输出(5)编译、链接和运行程序,程序运行结果如图10-5所示。图10-5例10.4运行结果第10章图形输出10.1.5颜

色设置对于绘图来说,颜色是一个重要的属性。WindowsGDI提供了一个独立于硬件的颜色接口。程序中提供的是一个逻辑颜色,GDI将程序代码中的逻辑颜色映射为计算机或其它输出设备上的适当颜色(近似色)或颜色组合(通过抖动实

现)。Windows使用一个32位无符号长整数来表示一种颜色,其数据类型为COLORREF。使用颜色的GDI函数都接受COLORREF参数。COLORREF的3个低位字节分别指定颜色的红、绿和蓝分量,高位字节为0,每一个分量的取值范围为

0~255,如图10-6所示。第10章图形输出…………b31b24b23b16b15b8b7b1b00蓝绿红图10-6COLORREF类型的颜色值第10章图形输出除了可以直接使用COLORREF类型的32位长整数指定颜色值外,Windows还提供了RGB宏用于设置颜色,将红、绿、蓝分量转换

为COLORREF类型的颜色值,其使用格式为:COLORREFRGB(BYTEbRed,BYTEbGreen,BYTEbBlue);其中,参数“bRed”、“bGreen”和“bBlue”分别用于指定颜色的红、绿、蓝分量,它们的取值范围为0~255。例如,RGB(0

,0,0)表示黑色,RGB(255,255,255)表示白色,即长整数0x00FFFFFF。可以使用GetRValue、GetGValue和GetBValue宏从COLORREF值中提取出8位红、绿、蓝分量。第10章图形输出GDI对COL

ORREF值的处理依赖于输出硬件设备的颜色分辨率和使用颜色的设备环境。如果输出硬件设备支持24位颜色,例如视频适配器,则COLORREF值可以直接转换成屏幕上的颜色。但若视频适配器只支持每像素4位或6位颜色,则会根据当前调色板的设置决定一次能同时显示的颜色。例

如,标准的VGA可以显示262144种不同的颜色(红、绿、蓝各6位),但是运行在分辨率为640×480模式下时只能同时显示16种不同的颜色值。更普遍的情况是视频适配器可以显示超过1670万种颜色,但只能同时显示256种颜

色。可以同时显示的256种颜色根据RGB值确定并编入适配器的硬件调色板中。其中有16种颜色是所有调色板都支持的“纯”色,如表10-6所示。第10章图形输出表10-6标准“纯”色RGB值颜色RGB分量值颜色RGB分量值黑色0,0,0中灰色128,128,128深红色128,0,0红色2

55,0,0深绿色0,128,0绿色0,255,0深黄色128,128,0黄色255,255,0深蓝色0,0,128蓝色0,0,255深紫色128,0,128紫色255,0,255深青色0,128,128青色0,255,255浅灰色192,192,192白色255,255,255第10

章图形输出当视频适配器不支持绘图函数中指定的COLORREF值时,GDI使用简单的颜色匹配算法将每个COLORREF值都映射给最接近的纯色。如果给生成画笔的函数传递一个COLORREF值,Windows就会给画笔分配一个最接近的

纯色;如果将COLORREF值传递给生成画刷的函数而又找不到匹配的纯色时,Windows就会使用纯色来抖动,以实现画刷颜色。许多使用颜色的GDI函数都使用COLORREF类型值作为参数。例如影响文本显示颜色的两个设备环境属性文本颜色(前景色)和背景颜色可以分别使用C

DC::SetTextColor和CDC::SetBkColor函数进行设置,其函数原型为:virtualCOLORREFSetTextColor(COLORREFcrColor);virtualCOLORREFSetBkColor(COLORREFcrColor);第10章图形输出这

两个函数将参数crColor设置为当前文本颜色(背景颜色)并返回先前的文本颜色(背景颜色)。例如:COLORREFoldTextColor;oldTextColor=pDC->SetTextColor(RGB(255,0,0));//设置文本颜色为红色pDC->SetBkColor(RGB(0

,0,0));//设置背景颜色为黑色pDC->TextOut(0,0,“黑色背景红色文字”);//输出文字pDC->SetTextColor(oldTextColor);//恢复原来的文本颜色第10章图形输出10.2画笔和画刷当在设备环境中绘制直线和曲线以及矩形

、椭圆等封闭图形时,Windows用设备环境当前的画笔绘制直线和曲线以及封闭图形的边框,使用设备环境当前的画刷填充图形内部。设备环境的默认画笔画出的是一个像素点宽的黑色实线,默认的画刷为白色画刷WHITE_BRUSH。如果需要使用不同风格的画笔和画刷,则必须重新为设备环境

定义画笔和画刷,并在绘图之前将其选入设备环境。在MFC应用程序中使用画笔和画刷的步骤大致相同:(1)创建画笔(画刷)。(2)将创建的画笔(画刷)选入设备环境。(3)输出图形。(4)还原设备环境先前的画笔(画刷)。第10章图形输出10.2.1画笔MFC的

CPen类封装了GDI画笔。1.创建画笔创建画笔最简单的方法是构造一个CPen对象,并给它传递定义画笔的参数,包括画笔的样式、宽度和颜色。CPen类的构造函数原型如下:CPen(intnPenStyle,intnWidth,COLORREFcrColo

r);其中,参数“nPenStyle”用于指定画笔的样式,其取值如表10-7所示;“nWidth”用于指定画笔宽度;参数“crColor”用于指定画笔的颜色。例如:CPenpen(PS_DASH,1,RGB(255,0

,0));创建画笔的第二种方法是调用CPen的缺省构造函数构造一个没有初始化的CPen对象,并调用CPen::CreatePen函数创建画笔。CreatePen函数原型为:BOOLCreatePen(intnPenSt

yle,intnWidth,COLORREFcrColor);第10章图形输出例如:CPenpen;pen.CreatePen(PS_DASH,1,RGB(255,0,0));创建画笔的第三种方法是构造一个没有初始化的CPen

对象,填写描述画笔特性的LOGPEN结构,然后调用CPen::CreatePenIndirect函数创建画笔。例如:CPenpen;LOGPENlogPen;logPen.lopnStyle=PS_DASH;logPenlopnWidth=1;lo

gPen.lopnColor=RGB(255,0,0);pen.CreatePenIndirect(&logPen);创建画笔需要三个特性参数:样式、宽度和颜色。上述三个例子创建的都是宽度为1的红色虚线画笔。传递给CPen构造函数和CreatePen的第一个参

数用于指定画笔的样式,即线的类型。表10-7列出了画笔样式。第10章图形输出表10-7画笔的基本样式样式说明样式说明PS_SOLID实线PS_DASHDOTDOT双点划线PS_DASH虚线PS_NULL空笔PS_DOT点线PS_IN

SIDEFRAME边框内实线PS_DASHDOT点划线第10章图形输出传递给CPen构造函数和CreatePen函数的第二个参数用于指定画笔的宽度。画笔宽度以逻辑值指定,其单位取决于当前设备环境的映射模式。可以创建任意宽度的PS_SOLID、PS_NULL和PS_INSIDEFRA

ME样式画笔,但PS_DASH、PS_DOT、PS_DASHDOT和PS_DASHDOTDOT样式画笔则必须是一个逻辑单位宽。无论是何种映射模式,若将画笔宽度指定为0,则任一样式的画笔宽度都为一个像素点宽。第10章图形输出2.选入画笔创建好画笔后

必须将其选入设备环境才能使用。函数CDC::SelectObject用于将GDI对象选入设备环境。SelectObject在CDC类中是一个重载函数,用于选择画笔的函数原型为:CPen*SelectObject(CPen*pPen);第10章图形输出其中,参数“pPen”指向将要被选入设备环境

的画笔对象。函数返回指向设备环境先前的画笔对象的指针。一般情况下,在使用SelectObject选择新的画笔时应保存先前的画笔对象,以便可以通过其返回值恢复设备环境先前的属性。例如:CPen*pOldPen,NewPen;NewPen.Create

Pen(PS_DASH,1,RGB(255,0,0));//创建宽度为1的红色点划线pOldPen=pDC->SelectObject(&NewPen);pDC->Ellipse(0,0,255,255);第10章图形输出3.还原画笔将画笔选入设备环境后,就可以使用该画笔绘图。当绘图结束

后,应该恢复设备环境先前的属性,此时只需要再次调用SelectObject,将上次调用此函数时保存的画笔选入设备环境即可。例如:pDC->SelectObject(pOldPen);//还原画笔由CGdiObjec

t派生类创建的画笔、画刷和其它对象都要占用内存空间,因此在使用完毕之后一定要删除它们。如果在栈上创建CPen、CBrush、CFont或其它GDI对象,那么在对象超出其作用域范围时,相关的GDI对象就会自动被删除。如果用new在堆上创建了一个CGdiObject派生类对

象,则在特定时刻一定要用delete删除它,以便调用它的析构函数。第10章图形输出在应用程序中可以通过调用CGdiObject::DeleteObject显式地删除GDI对象,以便释放其所占用的内存资源。如果是库存对象,即便是由CreateSt

ockObject创建的库存对象,也没必要专门去删除它。例如:pDC->SelectObject(pOldPen);//还原画笔NewPen.DeleteObject();//删除创建的画笔NewPen【例10

.5】编写一个单文档界面应用程序,用不同样式、宽度的画笔绘制圆。利用AppWizard创建一个单文档界面应用程序,项目名为EX10_5。在类CEX10_5View的成员函数OnDraw中添加如下黑体代码,根据创建的不同样式和宽度的画笔绘制圆。第10章图形输出voidCEX1

0_5View::OnDraw(CDC*pDC){CPen*pOldPen,NewPen;intnPenStyle[]={PS_SOLID,PS_DASH,PS_DOT,PS_DASHDOT,PS_DASHDOTDOT,PS_

NULL,PS_INSIDEFRAME};pDC->TextOut(80,10,"用不同样式的画笔画圆");CRectrect1(50,50,320,320);for(inti=0;i<7;i++){if(NewPen

.CreatePen(nPenStyle[i],1,RGB(0,0,0)))//用不同样式创建画笔第10章图形输出{pOldPen=pDC->SelectObject(&NewPen);//将画笔选入设备环境pDC->Ellipse(&rect1);rect1.DeflateRect(20,20

,20,20);//缩小椭圆外接矩形pDC->SelectObject(pOldPen);//恢复原来的画笔NewPen.DeleteObject();//删除GDI对象}else{MessageBox("创建画

笔失败!");}}第10章图形输出pDC->TextOut(400,10,"用不同宽度的画笔画圆");CRectrect2(350,50,620,320);for(i=0;i<7;i++){if(NewPen.CreatePen

(PS_SOLID,1+i,RGB(0,0,0))){pOldPen=pDC->SelectObject(&NewPen);pDC->Ellipse(&rect2);rect2.DeflateRect(20,20,20,20);pDC->Se

lectObject(pOldPen);NewPen.DeleteObject();}elseMessageBox("创建画笔失败!");}}第10章图形输出编译、链接和运行程序,运行结果如图10-7所示。图10-7例10.5运行结果第10章图形输出

10.2.2画刷当在设备环境中绘制矩形、椭圆等封闭图形时,Windows使用设备环境当前的画刷填充图形内部,设备环境缺省的画刷为白色画刷WHITE_BRUSH。通过创建GDI画刷并在绘图之前将其选入设备环境可以改

变图形的填充颜色和样式。MFC的CBrush类封装了GDI画刷。画刷有三种基本类型:纯色画刷、阴影画刷和图案画刷。纯色画刷填充的是单一颜色,如果显示硬件不支持直接显示纯色画刷的颜色,则Windows通过抖动处理来模仿该颜色。阴影画刷采用预先定义的线条图案填充图形,预

定义的线条图案共有六种。图案画刷使用指定的位图来填充图形。第10章图形输出创建画刷的第一种方法是使用类CBrush的构造函数直接创建画刷。与画刷的三种类型对应,类CBrush提供了三个不同的构造函数分别用于创建不同类型的画刷,其原型为:CBrush(COLORREFcrColo

r);CBrush(intnIndex,COLORREFcrColor);CBrush(CBitmap*pBitmap);第一个构造函数用于创建纯色画刷,其中的参数用于指定画刷的颜色;第二个构造函数用于创

建阴影画刷,两个参数分别指定画刷阴影的样式和颜色,画刷阴影样式共六种,如表10-8所示;第三个构造函数用于创建图案画刷,其中的参数用于指定画刷所使用的位图。例如:CBrushbrush(RGB(255,0,

0));创建了一个红色的纯色画刷。第10章图形输出表10-8阴影画刷的样式样式说明HS_BDIAGONAL从左向右45°角向下的阴影HS_CROSS水平和垂直交叉的阴影HS_DIAGCROSS45°角的交叉阴影HS_

FDIAGONAL从左向右45°角向上的阴影HS_HORIZONTAL水平阴影HS_VERTICAL垂直阴影第10章图形输出在使用阴影画刷时,Windows使用设备环境当前的背景色填充阴影线的空白处,默认背景色为白色。可以

使用CDC::SetBkColor改变设备环境的背景色,或用SetBkMode将背景模式由OPAQUE改为TRANSPARENT,禁止背景填充。创建画刷的第二种方法是使用类CBrush的缺省构造函数定义CBrush对象,然后调用CBrush类中的成

员函数创建画刷。函数CreateSolidBrush用于创建纯色画刷,其原型为:BOOLCreateSolidBrush(COLORREFcrColor);函数CreateHatchBrush用于创建阴影画刷,其原型为:BOOLCreateHatchBrush(intnInde

x,COLORREFcrColor);第10章图形输出函数CreatePatternBrush用于创建图案画刷,其原型为:BOOLCreatePatternBrush(CBitmap*pBitmap);创建画刷的第三种方法是构造一个没有初始化的CBr

ush对象,填写描述画刷特性的LOGBRUSH结构,然后调用CPen::CreateBrushIndirect函数创建画刷。此函数可以创建三种类型的画刷。例如,如下代码创建一个水平和垂直交叉的红色阴影线的阴影画刷:CBrushbrush;LOGBRUSHlogBrush;logBrush.l

bStyle=BS_HATCHED;logBrush.lbColor=RGB(255,0,0);logBrush.lbHatch=HS_CROSS;brush.CreateBrushIndirect(&logBrush);第10章图形输出为了在绘图中使用创建的画刷,

在绘图之前应将其通过CDC::SelectObject函数选入设备环境。与画笔一样,画刷使用结束后应该还原设备环境先前的画刷,也可以调用CGdiObject::DeleteObject显式删除画刷。【例10.6】编写一个单文档界面应用程序,利用不同的阴影画刷

绘制矩形。利用AppWizard创建一个单文档应用程序,项目名为EX10_6。在类CEX10_6View的成员函数OnDraw中添加如下黑体代码,根据创建的不同画刷绘制矩形。第10章图形输出voidCEX10_6Vi

ew::OnDraw(CDC*pDC){intnIndex[]={HS_BDIAGONAL,HS_CROSS,HS_DIAGCROSS,HS_FDIAGONAL,HS_HORIZONTAL,HS_VERTICAL};char*strIndex[]={“HS_BDIAGONAL”,

“HS_CROSS”,"HS_DIAGCROSS",“HS_FDIAGONAL”,“HS_HORIZONTAL”,"HS_VERTICAL"};COLORREFcrColor[]={RGB(255,0,0),RGB(0,255,0),RGB

(0,0,255),RGB(255,255,0),RGB(255,0,255),RGB(0,255,255)};CRectrect(10,30,50,60);CBrush*pOldBrush,NewBrush;for(inti

=0;i<6;i++)第10章图形输出{if(NewBrush.CreateHatchBrush(nIndex[i],crColor[i])){pOldBrush=pDC->SelectObject(&NewBrush);pD

C->TextOut(10+120*i,10,strIndex[i]);pDC->Rectangle(&rect);rect.OffsetRect(120,0);pDC->SelectObject(pOldBrush);NewBrush.DeleteObject();}elseMessag

eBox("创建画刷失败");}}第10章图形输出编译、链接和运行程序,运行结果如图10-8所示。图10-8例10.6运行结果第10章图形输出10.3绘图在成功设置设备环境、设备环境的属性和选择绘图工具后,就可以利用GDI绘图函数绘制各种不同的图形。Window

sGDI绘图函数比较多,这些函数封装在MFC的CDC类中。CDC中的绘图函数使用的坐标都是逻辑坐标。第10章图形输出10.3.1绘制点、直线和曲线MFC的CDC类中包含了许多用来绘制直线和曲线的成员函数。表10-9列出了一

些常用的绘制直线和曲线的成员函数。第10章图形输出表10-9绘制直线和曲线的常用CDC函数函数说明MoveTo将当前位置移动到指定坐标。在画线前设置SetPixel用指定的颜色在指定的坐标画一个像素点LineTo从

当前位置画一条直线到指定位置,并将当前位置移至直线的终点Arc画一个弧,画弧方向为从起点到终点逆时针方向ArcTo画一个弧并将当前位置移至弧的终点PolyLine画一条连接多个指定点的折线,不使用也不改变当前位置PolylineTo从当前位置开始画一条连接

多个点的折线,并将当前位置移至折线终点PolyBezier画一条或多条贝赛尔样条曲线,不使用也不改变当前位置PolyBezierTo画一条或多条贝赛尔样条曲线,第一条样条曲线从当前位置开始,并将当前位置移至最后一条

样条曲线的终点PolyDraw通过一组点画一条折线和贝赛尔样条曲线,并将当前位置移至折线或样条曲线的终点第10章图形输出【例10.7】编写一个单文档界面应用程序,在视图窗口的客户区域内画一条正弦曲线。利用AppWizard创建一个单文档界面应用程序框架,项目名为EX10_7。在视

图类CEX10_7View的实现文件EX10_7View.cpp的开始处添加如下命令:#include"math.h"#definePI3.1415926#defineSEGMENTS500第10章图形输出在视图类CEX10_7View的成员函数OnDraw中添加如下黑体代码:voidCE

X10_7View::OnDraw(CDC*pDC){CRectrect;GetClientRect(&rect);//获取客户区域大小intnWidth=rect.Width();//计算客户区域宽度intnHeight=rect.Height

();//计算客户区域高度CPointaPoint[SEGMENTS];//定义画折线的坐标点数组for(inti=0;i<SEGMENTS;i++)//根据正弦曲线初始化坐标点{aPoint[i].x

=(i*nWidth)/SEGMENTS;aPoint[i].y=(int)((nHeight/2)*(1-(sin(2*PI*i/SEGMENTS))));}第10章图形输出pDC->MoveTo(0,nHeig

ht/2);pDC->LineTo(nWidth,nHeight/2);//画水平坐标轴pDC->Polyline(aPoint,SEGMENTS);//画折线来近似正弦曲线}编译、链接和运行程序,运行结果如图10-9所示。第10章图形输出图10

-9例10.7运行结果第10章图形输出在使用这些绘图函数时需要注意其绘图的起点。有些函数的起点是从当前位置开始的,如LineTo、PolylineTo和PolyBezierTo等。另外,其中有些函数绘制后不改变当前位置,而另一些函数会改变当前位置。可以调用CDC::Get

CurrentPosition函数获取当前位置坐标。所有画直线和曲线的GDI函数都有一个特点:不画最后一个点。例如用下面的语句画一条从(0,0)到(100,100)的直线:pDC->MoveTo(0,0);pD

C->LineTo(100,100);则从(0,0)到(99,99)位置上的点都被设置成该直线的颜色,但点(100,100)上的颜色保持不变。如果需要画出该线的最后一个点,则必须自己再调用CDC::SetPixel画一次该点。第10

章图形输出10.3.2画封闭图形GDI不仅提供了画直线和曲线的函数,还提供了画椭圆、矩形、扇形、弦形和多边形等封闭图形的函数。同样,MFC的CDC类将这些相关的GDI函数封装在类的成员函数中。表10-10列出了常用的画封闭图形

的CDC函数。第10章图形输出表10-10用来画封闭图形的常用CDC函数函数说明Chord画一个弦形。弦形是由一条弧和连接弧两个端点的弦构成的封闭图形Ellipse画一个圆或椭圆Pie绘制扇形。扇形是一条弧和从弧的两个端点到中心的连线构成的封闭图形Polygon绘制连接两个或多个顶点的多边形

Rectangle画直角矩形RoundRect画圆角矩形第10章图形输出在画这些封闭图形时,Windows用选入设备环境的当前画笔画图形的边界,用选入设备环境的当前画刷填充图形内部区域。【例10.8】编写一个单文档界面应用程序,在视图窗口的客户区域用扇形显示用户对生

活质量调查的结果。在对生活质量的调查中,表示满意、基本满意、不满意和非常不满意的比例分别为34%、43%、14%和9%。利用AppWizard创建一个单文档界面应用程序框架,项目名为EX10_8。在视图类CEX10_8View的实现文件EX10_8Vie

w.cpp的开始添加如下命令:#include"math.h"#definePI3.1415926第10章图形输出在视图类CEX10_8View的成员函数OnDraw中添加如下黑体代码:voidCEX10_8V

iew::OnDraw(CDC*pDC){doublefProportion[]={0.34,0.43,0.14,0.09};CRectrect;GetClientRect(&rect);//将视口原点移至客户区中心pDC->SetViewportOrg(rect.Width

()/2,rect.Height()/2);CRectpieRect(-150,-100,150,100);//画扇形的外接矩形CBrush*pOldBrush,NewBrush;intnBrushStyle[]={HS_CROSS,HS_BDIAGONAL,HS_DIAGC

ROSS,HS_FDIAGONAL};第10章图形输出intx1=0;inty1=-1000;doublefSum=0.0;pDC->SetBkColor(RGB(192,192,192));//设置填充画刷间隙的颜色for(inti=0;i<4;i++)

{fSum+=fProportion[i];doublerad=fSum*2*PI+PI;intx2=(int)(sin(rad)*1000);inty2=(int)(cos(rad)*1000*3)/4;NewBrush.CreateHatchBrush(nBrushStyle[i],R

GB(0,0,0));pOldBrush=pDC->SelectObject(&NewBrush);pDC->Pie(pieRect,CPoint(x1,y1),CPoint(x2,y2));第10章图形输出x1=x2;y1=y2;pDC->SelectObject(pOldBr

ush);NewBrush.DeleteObject();}}编译、链接和运行程序,程序运行结果如图10-10所示。第10章图形输出图10-10例10.8运行结果第10章图形输出10.4文本和字体在应用程序中

文本输出是必不可少的,WindowsGDI具有丰富的文本输出能力。事实上,在Windows中,文本也是作为图形来处理的。文本输出是按照所选用的字体的格式绘制出来的。所有的GDI文本输出函数都使用当前选入设备环境的字体属性。在应用程序中除了可以使用系统预定义的字体外,还可以自

定义字体,并选入设备环境。第10章图形输出10.4.1文本输出WindowsGDI文本处理函数被封装在MFC的CDC类中。编程时最常用的文本输出函数是CDC::TextOut,其函数原型为:virtualB

OOLTextOut(intx,inty,LPCTSTRlpszString,intnCount);BOOLTextOut(intx,inty,constCString&str);该函数用于在指定逻辑坐标(x,y)处输出单

行文本。此函数在输出文本时不能自动换行。要想输出多行文本可以使用CDC::DrawText函数,其函数原型为:virtualintDrawText(LPCTSTRlpszString,intnCount,LPRECTlpRect,UINTnFormat);intDrawText(cons

tCString&str,LPRECTlpRect,UINTnFormat);第10章图形输出其中,参数“lpszString”指定要输出的字符串,如果参数“nCount为-1,则字符串必须以“\0”结尾。“n

Count”指定输出的字符个数,若为-1,则函数自动计算字符个数。“lpRect”指定格式化文本的矩形区域(使用逻辑坐标)。“nFormat”指定格式化文本的方式,如对齐方式、是否单行显示等(其取值可以参考MSDN)。例如:pDC->DrawText(“文

本输出示例”,-1,CRect(10,10,200,200),DT_SINGLELINE|DT_CENTER|DT_VCENTER);将文本在指定的矩形区域内垂直与水平居中显示为单行。与TextOut函数工作方式相似的另一个函数为TabbedTextOut,如果输

出的字符串中包含制表符“\t”,则此函数将按照指定的制表符位置将其展开为空格。第10章图形输出函数ExtTextOut在指定的矩形区域内输出文本,此矩形区域可以被当前背景色填充,也可以作为一个剪裁区域对文本进行剪裁。CDC类中与文本输出有关的成员函数比较

多,常用的函数如表10-11所示。第10章图形输出表10-11CDC类中的文本处理函数函数说明TextOut在指定位置或当前位置输出一行文本ExtTextOut在矩形区域内输出一行文本,并给矩形区域填充背景色或用矩形区域剪裁文本TabbedTextOut在指定位置输出文本,并将字符串中的

制表符按指定位置展开DrawText在指定的矩形区域内输出格式化文本GetTextExtent根据当前设备环境的字体属性计算一行文本的宽度和高度GetTextAlign获取当前文本的对齐方式SetTextAlign设置

显示文本的对齐方式GetTextMetrics获取当前字体的规格(如字符高度、字符平均宽度等)GetTextFace获取当前字体的字体名SetTextColor设置设备环境的文本输出颜色SetBkCol

or设置设备环境的背景色,即确定输出文本下的填充色GetTextCharacterExtra获取显示文本的字符间距SetTextCharacterExtra设置输出文本的字符间距SetTextJustification确定对齐文本时需要增加的宽度第10章图形输出10.4.

2设置文本的设备环境属性当使用GDI文本输出函数输出文本时,GDI设备环境的属性决定了文本输出的效果。默认情况下,文本颜色为黑色,以白色填充文本背景,字符间距被设置为0,文本为左对齐。在输出文本前可以使用相应的CDC成员函数改变这些属性值。函数SetTextCo

lor用指定的颜色设置文本颜色,函数原型为:virtualCOLORREFSetTextColor(COLORREFcrColor);其中,参数“crColor”指定文本的RGB颜色值。可以通过调用Ge

tTextColor来获取当前文本的颜色。字符笔划之间的空隙根据背景模式和背景颜色的设置来填充。缺省背景模式为OPAQUE,即Windows使用背景颜色填充字符笔划之间的空隙区域。使用函数SetBkColor用指定颜色设置背景颜色,函数原型

为:virtualCOLORREFSetBkColor(COLORREFcrColor);第10章图形输出函数SetBkMode用于设置背景模式,函数原型为:intSetBkMode(intnBkMode);其中,参数“n

BkMode”指定设置的背景模式。若将背景模式设置为TRANSPARENT,则Windows将忽略背景颜色,不给字符笔划之间的间隙着色。缺省时,函数TextOut、TabbedTextOut和ExtTex

tOut以指定的坐标值确定文本最左侧字符的左上角,即左对齐。文本对齐方式是设备环境的一个属性。函数SetTextAlign用于设置文本输出时的对齐方式,函数原型为:UINTSetTextAlign(UINTnFlags);其中,参数“nFlags”指定文本对齐标志,其值可以

是表10-12所列之一或多个的组合。第10章图形输出表10-12文本对齐标记对齐标记nFlags说明TA_CENTER将文本边界矩形的水平中心与点对齐TA_LEFT将文本边界矩形的左边界与点对齐(默认

设置)TA_RIGHT将文本边界矩形的右边界与点对齐TA_BASELINE将所选字体的基线与点对齐TA_BOTTOM将文本边界矩形的下边界与点对齐TA_TOP将文本边界矩形的上边界与点对齐(默认设置)TA_NOUPDATECP

调用文本输出函数后,不更新当前位置(默认设置)TA_UPDATECP调用文本输出函数后更新当前x位置。新位置在文本边界的右边第10章图形输出当用TA_UPDATECP标志调用SetTextAlign时,TextOut将忽略传递给它的x

和y坐标,而改用当前设备环境的当前位置,并且每输出一个字符串,TextOut就更新一次当前位置的x值。这个特性的用处之一是调节在同一行上输出的两个或两个以上字符串间的距离。默认情况下,文本输出时的字符间距为0,这时,Windows在字符间不加入任何空隙。函数SetTextCharact

erExtra用于设置字符间的间距,其函数原型为:intSetTextCharacterExtra(intnCharExtra);其中,参数“nCharExtra”用于指定在每个字符间插入间隔的大小(逻辑值)。第10章图形输出10.4.3获取字体信息在Windows中,字符大小并不

完全相同,如宽度不同,或高度不同,或字符行距和间距也不相同。在输出文本时要充分考虑和利用这些字体信息。可以使用CDC::GetTextMetrics函数获取当前设备环境字体的完整描述,函数原型为:BOOLGetTextMetrics(LPTEXTME

TRIClpMetrics)const;第10章图形输出当前设备环境字体的完整描述存放在TEXTMETRIC结构中,TEXTMETRIC结构定义为:typedefstructtagTEXTMETRIC{/*tm*/inttmHeight

;//字符的高度(为tmAscent和tmDescent成员之和)inttmAscent;//字符基线以上的高度inttmDescent;//字符基线以下的高度inttmInternalLeading;//包含在tmHeight内的字符内部行距intt

mExternalLeading;//两行之间的行距(外部行距)inttmAveCharWidth;//字体中所有字符的平均宽度inttmMaxCharWidth;//字体中最宽字符的宽度inttmWeigh

t;//字体的粗细度BYTEtmItalic;//字符倾斜,0值表示非斜体第10章图形输出BYTEtmUnderlined;//指定下划线,0表示不带下划线BYTEtmStruckOut;//指定删除线,0表示不带删除线BYT

EtmFirstChar;//字体中第一个字符的值BYTEtmLastChar;//字体中最后一个字符的值BYTEtmDefaultChar;//字体中所没有的字符的替代字符BYTEtmBreakChar;//文本对齐时作为分隔符的字

符BYTEtmPitchAndFamily;//字符间距和物理字体族BYTEtmCharSet;//字体的字符集inttmOverhang;//每个合成字体字符串的附加宽度inttmDigitizedAspectX;//为输出设备设计的水平尺寸inttmDigitiz

edAspectY;//为输出设备设计的垂直尺寸}TEXTMETRIC;第10章图形输出该结构定义中关于字符高度的5个值如图10-11所示。tmExternalLeadingtmInternalLeadingtmAscent基线tmDescenttmHeight图1

0-11定义字体中字符高度的5个值第10章图形输出与文本行距有关的两个值是tmExternalLeading和字符高度tmHeight,有了这两个值,就可以不必关心何种字体以及字体大小的情况,要确定下一行文本的位置,只需要将这两个值相加即可。函数CDC::GetTextExtent返回指定字符

串在当前设备环境字体下的宽度,以逻辑单位表示。函数原型为:CSizeGetTextExtent(LPCTSTRlpszString,intnCount)const;CSizeGetTextExtent(constCString&str)const;如果字

符串中含有制表符,则可以调用GetTabbedTextExtent函数获得字符串的宽度。【例10.9】编写一个单文档界面应用程序,在视图窗口中显示当前设备环境下字体的一些信息。第10章图形输出利用AppWizard创建一个单文档界面应用程序框架,项目名设置为EX10_9。在视图类CEX

10_9View的实现文件EX10_9View.cpp的头部添加如下宏定义:#defineNUMLINES(int)(sizeof(textmetrics)/sizeof(textmetrics[0]))在文件EX10_9View.cpp中所有类的成员函数定义前面添加如下结构体

数组的定义:struct{char*szLabel;char*szDesc;}第10章图形输出textmetrics[]={“tmHeight”,"字符高度",“tmAscent”,"字符基线以上的高度",“tmDescent”,"字符基线以下的高度","tmInternalLead

ing","字符内部行距","tmExternalLeading","行间距(外部行距)","tmAveCharWidth","字符的平均宽度","tmMaxCharWidth","最宽字符的宽度","tmFirstChar","

第一个字符","tmLastChar","最后一个字符","tmDefaultChar","替代字符","tmBreakChar","分隔符","tmPitchAndFamily","字符间距和字体族"};第10章图形输出在视图类的成员函数OnDraw中添加如下的

黑体代码:voidCEX10_9View::OnDraw(CDC*pDC){intcxChar,cyChar;inti;TEXTMETRICtm;CStringstr[NUMLINES];pDC->GetText

Metrics(&tm);//获取字体信息cxChar=tm.tmAveCharWidth;cyChar=tm.tmHeight+tm.tmExternalLeading;//每行文本显示的高度str[0].Format("%5d",tm.tmHeight);str[1].Fo

rmat("%5d",tm.tmAscent);第10章图形输出str[2].Format("%5d",tm.tmDescent);str[3].Format("%5d",tm.tmInternalLeading);

str[4].Format("%5d",tm.tmExternalLeading);str[5].Format("%5d",tm.tmAveCharWidth);str[6].Format("%5d",t

m.tmMaxCharWidth);str[7].Format("%c",tm.tmFirstChar);str[8].Format("%c",tm.tmLastChar);str[9].Format("%c",tm.tmDefaultChar);st

r[10].Format("%c",tm.tmBreakChar);str[11].Format("%d",tm.tmPitchAndFamily);pDC->SelectStockObject(SYS

TEM_FIXED_FONT);//选入库存字体for(i=0;i<NUMLINES;i++)第10章图形输出{pDC->TextOut(cxChar,cyChar*(1+i),textmetrics[i].szLabel);

pDC->TextOut(cxChar+22*cxChar,cyChar*(1+i),textmetrics[i].szDesc);pDC->SetTextAlign(TA_RIGHT|TA_TOP);//设置文本右对齐pDC->TextOut(cxChar+22*cxChar+40*cxCh

ar,cyChar*(1+i),str[i]);pDC->SetTextAlign(TA_LEFT|TA_TOP);//恢复左对齐}}编译、链接和运行程序,运行结果如图10-12所示。第10章图形输出图10-12例10.9运行结果第10章图形输出10.4

.4字体当使用CDC文本输出函数输出文本时,Windows使用当前选入设备环境的字体绘制文本,默认为系统字体SYSTEM_FONT。第10章图形输出字体是指一套具有大小、风格和字样的字符。字样是指字体中字符和符号的样式和文本的视觉外观。根据字符的宽度特性,Wind

ows中的字体分为两种:固定宽度字体和可变宽度字体。固定宽度字体的字符宽度相同,主要用于Windows3.0及以前的版本;可变宽度字体的字符宽度根据需要而并不相同。根据字体的构成技术,Windows的字体分成三种类型:光栅字体、矢量字体和TrueType字体。光栅字体即点阵字体,每个字符都是以位

图像素模式存储的。每种光栅字体都是按特定纵横比和大小设计的,在以原尺寸显示时效果最好。通过简单的复制行和列上的像素,Windows能按比例缩放光栅字体。但由于会出现锯齿状,因此显示出来的字往往不好看。光栅字体的优点是显示快,因此,Windows提供了MsSansSeri

f光栅字体,广泛用在菜单、命令按钮、单选按钮和其它对话框控件上。矢量字体由一系列线段构成字体,可以任意缩放,但性能较差,在尺寸太小时不容易辨认,尺寸太大时字符又显得单薄。矢量字体对绘图仪最适合。第10章图形输出最好用的

字体是TrueType字体,它由线条和样条曲线来定义字符轮廓,能按比例缩放为任意尺寸。TrueType字体既可以用于视频显示器上,又可以用于打印机上,从而实现了真正的“所见即所得”。与画笔和画刷一样,字

体也是一个GDI对象。在MFC中,CFont类封装了GDI字体。Windows本身提供了一些库存字体,不需要创建,可以直接将其选入设备环境中使用。此外,还可以根据需要创建自定义字体,从而使应用程序输出丰富多

样的文本外观。1.使用库存字体Windows提供了6种库存字体,可以通过CDC::SelectStockObject将库存字体选入设备环境。Windows提供的6种库存字体如表10-13所示。第10章图形输出表10-13Windows库存字体库存字体说明A

NSI_FIXED_FONTANSI标准固定宽度字体ANSI_VAR_FONTANSI标准可变宽度字体DEVICE_DEFAULT_FONT与设备有关的字体OEM_FIXED_FONT与OEM相关的固定宽度字体SYSTEM_FONT可变宽度系统字

体。默认情况下,Windows用系统字体显示菜单、对话框控件字体和其它文本SYSTEM_FIXED_FONT固定宽度系统字体例如,例10.9中使用如下代码选择SYSTEM_FIXED_FONT:pDC->SelectSt

ockObject(SYSTEM_FIXED_FONT);第10章图形输出2.创建字体直接使用Windows提供的库存字体可以满足一般的需要,还可以根据需要创建自己的字体。创建字体并不是创建一种新的物理字体(以文件形式存储于磁盘上),而是创建一种

逻辑字体。逻辑字体是一种字体特征描述,如高度、宽度、字符集、粗细、角度等。创建字体的方式是首先定义一个CFont的对象,然后通过调用CFont的成员函数CreateFont、CreateFontIndirect、CreatePointFont或CreatePointFont

Indirect创建字体,最后通过调用CDC::SelectObject将创建的字体选入设备环境。第10章图形输出创建字体最简单的方法是使用函数CreatePointFont,该函数以点为单位指定字体尺寸。

一个点(point)相当于1/72英寸,12点字体中的字符有1/6英寸高。函数原型为:BOOLCreatePointFont(intnPointSize,LPCTSTRlpszFaceName,CDC*pDC=NULL);其中,参数“nPointSize”指定字体高度点数的10倍,例如要创建12

点的字体,则此参数指定为120。“lpszFaceName”指定字样名称,为CString对象或以“\0”结尾的字符串。pDC为指向使用字体的设备环境的CDC对象,Windows根据此设备环境的属性将字体高度的点数nPointSize转换为

逻辑单位,若它为NULL,则根据屏幕设备环境进行转换。第10章图形输出例如,创建12点屏幕字体只需要如下两行代码:CFontfont;font.CreatePointFont(120,"TimesNewRoman");使用CreatePointFo

nt不能指定字体的其它特征,例如加粗、倾斜等,如果需要指定字体的其它特征,可以使用函数CreatePointFontIndirect,其函数原型为:BOOLCreatePointFontIndirect(constLOGFONT*lpLogFont,CDC*pDC=NULL)

;其中,参数“lpLogFont”为指向LOGFONT结构的指针。结构LOGFONT用于定义字体的所有特征,其定义为:第10章图形输出typedefstructtagLOGFONT{//lfLONGlfHeight;//以逻辑单位表示的字体高度,为0则采用系统默认值LONGlfWidth

;//以逻辑单位表示的字体宽度,为0则由系统根据高宽比取最佳值LONGlfEscapement;//文本行与X轴间的角度,以1/10度为单位LONGlfOrientation;//每个字符的基线与X轴间的角度,以1/10度为单位

LONGlfWeight;//字体的粗细,取值范围为0~1000,400为正常字体,700为加粗BYTElfItalic;//若设置为TRUE,则表示字体倾斜BYTElfUnderline;//若设置为TRUE,则表示字体加下划线第10章图形输出BYTElfStrikeOut;//若设置为

TRUE,则表示字体加删除线BYTElfCharSet;//字体所属字符集,如ANSI_CHARSET、DEFAULT_CHARSET等BYTElfOutPrecision;//指定输出精度,一般取默认值OUT_DEFAULT_PRECISBYTElfClipPrecision;//指定剪裁精

度,一般取默认值CLIP_DEFAULT_PRECISBYTElfQuality;//指定输出质量,一般取默认值DEFAULT_QUALITYBYTElfPitchAndFamily;//指定字体间距和字体族,一般取默认值DEFAULT_PITCHTCHARlfFa

ceName[LF_FACESIZE];//字体的字样名(使用Windows系统中的字体名)}LOGFONT;第10章图形输出需要说明的是,在使用函数CreatePointFontIndirect时,LOGFONT的成员lfHeight为字体高

度点数的10倍,而不使用逻辑单位。在创建时,若指定的lfFaceName字样名在Windows系统中没有安装,则Windows会选择系统中相近的字样,而不让创建字体失败。通过调用系统内部的字体映射算法,GDI选择出与指定字样最接近的一

个,因此结果往往不是用户所期望的。第10章图形输出例如,如下代码调用CreatePointFontIndirect函数创建一个12点、加粗、倾斜的宋体字体:CFontfont;LOGFONTlf;ZeroMemory(&lf,sizeof(lf));lf.lfHeight=120;lf

.lfWeight=FW_BOLD;lf.lfItalic=TRUE;::lstrcpy(lf.lfFaceName,"宋体");font.CreatePointFontIndirect(&lf);第10章图形输出函数CreateFont将创建字体时需要指定的特征作为参数,函数原型为:

BOOLCreateFont(intnHeight,intnWidth,intnEscapement,intnOrientation,intnWeight,BYTEbItalic,BYTEbUnderline,BYTEcStrikeOut,BYTEnCh

arSet,BYTEnOutPrecision,BYTEnClipPrecision,BYTEnQuality,BYTEnPitchAndFamily,LPCTSTRlpszFacename);第10章图形输出使

用CreateFont函数时,一般需要向设备环境查询垂直方向上每英寸内像素的逻辑个数,并将点转换为像素。例如创建12点宋体字体的方法如下:CFontfont;intnHeight=-((pDC->GetDeviceCaps(LOGPIXE

LSY)*12)/72);font.CreateFont(nHeight,0,0,0,FW_NORMAL,0,0,0,DEFAULT_CHARSET,OUT_CHARACTER_PRECIS,CLIP_CHARACTER_P

RECIS,DEFAULT_QUALITY,DEFAULT_PITCH|FF_DONTCARE,"宋体");第10章图形输出调用CreateFontIndirect函数时需要传递一个指向LOGFONT结构的指针作为

参数,函数原型为:BOOLCreateFontIndirect(constLOGFONT*lpLogFont);【例10.10】编写一个单文档界面应用程序,创建不同的字体,根据创建的字体输出相应的文本串。利用AppWizard创建一个单文档界面应用程序框架,项目名设置为EX10_10,在视

图类CEX10_10View的实现文件EX10_10View.cpp头部的所有类成员函数的定义前面添加如下结构体数组的定义:char*facename[]={"宋体","楷体_GB2312","黑体","隶书","Arial","Aria

lBlack","华文彩云","TimesNewRoman"};第10章图形输出在视图类的成员函数OnDraw中添加如下的黑体代码:voidCEX10_10View::OnDraw(CDC*pDC){intnHeight;TEXTMETRICtm;CStri

ngstrText;intnPoint=10,j=0,nPos=10;for(inti=0;i<8;i++){CFontfont;nHeight=-((pDC->GetDeviceCaps(LOGPIXELSY)*(nPoint+j))/72);font.

CreateFont(nHeight,0,0,0,FW_THIN+100*i,0,0,0,第10章图形输出DEFAULT_CHARSET,OUT_CHARACTER_PRECIS,CLIP_CHARA

CTER_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH|FF_DONTCARE,facename[i]);CFont*pOldFont=pDC->SelectObject(&font);strText.Format("Thisis%d-Poin

t%s",nPoint+j,facename[i]);pDC->TextOut(10,nPos,strText);pDC->GetTextMetrics(&tm);nPos+=tm.tmHeight+tm.tmExternalLeading;pDC->Se

lectObject(pOldFont);j+=2;}}第10章图形输出编译、链接和执行程序,程序的输出结果如图10-13所示。图10-13例10.10运行结果第10章图形输出在调用CreateFontIndirect和CreatePointF

ontIndirect时,通过给LOGFONT结构的lfEscapement和lfOrientation成员指定与期望的旋转角度(用度表示)成10倍的数值,并按正常方式输出,可以显示旋转文本。在调用CreateFont函数时,利用参数nEscapeme

nt和nOrientation也能旋转文字。第10章图形输出【例10.11】显示旋转文字示例。利用AppWizard生成单文档界面应用程序,项目名为EX10_11。在视图类的OnDraw成员函数中添加如下黑体代码:voidCEX10_11View::OnD

raw(CDC*pDC){CRectrect;GetClientRect(&rect);pDC->SetViewportOrg(rect.Width()/2,rect.Height()/2);for(int

i=0;i<3600;i+=150){LOGFONTlf;::ZeroMemory(&lf,sizeof(lf));第10章图形输出lf.lfHeight=140;lf.lfWeight=FW_BOLD;lf.lfE

scapement=i;lf.lfOrientation=0;::lstrcpy(lf.lfFaceName,"宋体");CFontfont;font.CreatePointFontIndirect(&lf)

;CFont*pOldFont=pDC->SelectObject(&font);pDC->TextOut(0,0,"旋转文字示例");pDC->SelectObject(pOldFont);}}第10章图形输出编译、链接和运行程序,运行结果如图10-14所示。图

10-14例10.11运行结果第10章图形输出习题1.什么是GDI?它有什么功能?MFC将GDI函数封装在哪个类中?2.什么是设备环境?如何获取设备环境?3.CPaintDC、CClientDC和CWindowDC各代表什么设备

环境?主要用在何处?4.设备环境包括哪些属性?说明各种属性的默认值。5.绘图模式起什么作用?6.什么是设备坐标系统?什么是逻辑坐标系统?7.映射模式有什么作用?Windows定义了哪几种映射模式?如何设置映射模式?第10章图形输出8.利用SetW

indowOrg将窗口坐标原点设置为(100,100),然后绘制一个矩形(100,100,300,300)。9.如何实现逻辑坐标到设备坐标的转换?如何实现设备坐标到逻辑坐标的转换?10.在例10.4中,如果不进行坐标转换,会出现什么情况?如果使用DptoLP,如何实现例10.4的功能?1

1.Windows中保存颜色值的数据类型是什么?如何使用RGB宏设置颜色?12.画笔主要完成什么功能?创建画笔有哪些方法?简述创建画笔的步骤。13.画刷主要完成什么功能?简述创建画刷的方法和步骤。14.编写程序,在视图窗口中绘制一条贝赛尔样条曲

线。第10章图形输出16.在应用程序中如何使用库存GDI对象?17.在应用程序中如何创建和使用自定义字体?18.编写一个SDI应用程序,设置映射模式为MM_TWIPS,在视图窗口中输出一行18点的楷体文本,文

本颜色为白色,背景为黑色。19.如何计算每行文本所占用的高度?20.编写一个SDI应用程序,设置不同的文本对齐方式,利用TextOut在每种对齐方式下输出一行文本。

小橙橙
小橙橙
文档分享,欢迎浏览!
  • 文档 25747
  • 被下载 7
  • 被收藏 0
相关资源
广告代码123
若发现您的权益受到侵害,请立即联系客服,我们会尽快为您处理。侵权客服QQ:395972555 (支持时间:9:00-21:00) 公众号
Powered by 太赞文库
×
确认删除?