MFC画板程序教程_第1页
MFC画板程序教程_第2页
MFC画板程序教程_第3页
MFC画板程序教程_第4页
MFC画板程序教程_第5页
已阅读5页,还剩56页未读 继续免费阅读

下载本文档

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

文档简介

本文格式为Word版,下载可任意编辑——MFC画板程序教程第四章屏幕绘图

4.1、MFC绘图的基本知识

4.1.1、设备描述表(devicecontext)的概念

绝大多数的Windows应用程序都要向不同的输出设备(打印机、屏幕)上绘制文本和图形。由于Windows是一个具有与设备无关性的操作系统,所以任何向屏幕上进行输出的功能都要间接地通过一个叫做设备描述表DC(devicecontext)的对象(简称为DC对象)来完成。用户向设备描述表对象提出输出的要求,然后由Windows自己来调用具体输出设备的驱动程序,及完成实际的输出工作。使用设备描述表带来的最大的好处就是输出格式的一致性,由于输出不再是直接针对具体的设备,而是通过统一格式的设备描述表间接地实现。设备描述表实际上是一种Windows的数据结构,它保存了设备(打印机、屏幕等)的绘图属性和绘图函数。设备描述表对象就是设备描述表数据结构的一个具体的实例,它提供了一个绘图的环境,所有的绘图工作都要通过它来实现。MFC提供了不同类型的设备描述表类,每一个类都封装了代表Windows设备描述表的句柄(HDC)和函数。因此,使用MFC获取设备描述表的操作比使用WindowsAPI方法简单的多。

围绕设备描述表,MFC还提供了一系列与其协同使用的绘图工具对象,这其中包括:画笔对象、刷子对象以及字体对象等等。它们的工作流程是这样的:首先对设备描述表进行设置,即获取设备描述表对象;然后选择进行输出所需要的绘图工具;最终用设备描述表对象的输出函数绘制图形。

4.1.2、窗口、客户区和非客户区的概念

窗口是Windows应用程序基本的操作单元,是其运行及与用户进行交互的基本平台。屏幕输出的目标一般都是窗口内的客户区,它不包括窗口的边框、水平和垂直滚动条、状态条、工具条、菜单栏和标题栏。窗口内的客户区是一个万能的输出区域,可以接受无论是图形、文本、位图、还是其他类型的数据(例如OLE对象)。窗口内除客户区之外的区域即为非客户区。图4-1显示了窗口内的客户区、非客户区及其相关部分的位置。

1

图4-1窗口内的客户区与非客户区

4.1.3、绘图类

MFC提供了不同类型的设备描述表的类(绘图类):CDC、CPaintDC、CClientDC、CWindowDC和CmetafileDC。其中CDC类是MFC绘图类的根类,其它的绘图类都是CDC类的派生类。CDC类包含了绘图所需的所有成员函数。其它的派生类,除了CmetafileDC类之外,都仅仅是构造函数和析构函数的不同。

1.CDC类

CDC类是MFC绘图类的根类,它是一个功能十分完全的类,包含170多个成员函数和数据成员。使用它可以访问整个显示设备。

使用CDC类必需首先调用Win32API的BeginPaint()函数为重绘工作做一些准备工作,在完成绘制之后还需用Win32API的EndPaint()函数来终止绘制工作。所有的绘图操作都必需在这两个函数之间完成。

2.CPaintDC类

CPaintDC类是CDC类的派生类,其绘图控制区为窗口的客户区。它是OnPaint()函数使用的绘图类,亦即用来响应Windows消息WM_PAINT(窗口刷新)的成员函数的

2

绘图类。因此,假使为了维护图形的完整性,而需要重新编写视窗的OnPaint()函数时,就必需使用CPaintDC类来定义一个绘图对象。

使用CPaintDC类绘图时,必需发出让包含要绘制图形的窗口刷新的指令,才能在窗口重画时,将图形绘制到客户区上,当然客户区内的其它图形同时也会重画。也就是说CPaintDC类不可以实时的将图形绘制到客户区上。

CPaintDC类封装了Win32API的BeginPaint()函数和EndPaint()函数。

3.CClientDC类

CClientDC类也是CDC类的派生类,其绘图控制区为窗口的客户区,该类可以实时的将图形绘制到客户区上。它是为不响应Windows消息WM_PAINT的成员函数提供的绘图类,亦即在OnPaint()函数中不使用CClientDC类。

CClientDC类封装了Win32API的GetDC()函数和ReleaseDC()函数。

4.CWindowDC类

CWindowDC类也是CDC类的派生类,其绘图控制区为整个窗口区域,既包括客户区,也包括非客户区,其它方面与CClientDC类似。

与CClientDC类相比,CWindowDC类更适用于框架窗口,亦即CWindowDC类一般在框架窗口类(CMainFrame)中引用。在视窗类(如CtestView类)中引用CWindowDC类时,由于视窗类只能管理客户区,所以并不能在非客户区绘图。

与CClientDC类一样,CWindowDC类也封装了Win32API的GetDC()函数和ReleaseDC()函数。

5.CmetafileDC类

CmetafileDC类是用于创立Windows图元文件的设备描述表,它也是CDC类的派生类。Windows图元文件包含了一系列GDI(GraphicsDeviceInterface)绘图命令。它不常用,假使使用它,必需自己调用OnPrepareDC函数。

3

4.1.4、绘图类的引用方法

一般状况下,应用程序的绘图工作都要在视图(View)类中进行,由AppWizard生成的程序中,有一个视图类的成员函数OnDraw,自动实现了在视图类中引用CDC类,这是由MFC程序内部的一个特别机制实现的。当视图窗口绘制或重绘制(窗口刷新消息WM_PAINT)时,都要调用OnDraw函数。

在前面例子test中的testView.cpp文件中可以找到OnDraw函数,其自动生成的代码如下:

//CTestViewdrawing

voidCTestView::OnDraw(CDC*pDC){??//TODO:adddrawcodefornativedatahere//用户在此添加代码。}

其中,pDC就是一个设备描述表类CDC对象的指针,在此函数中,可以通过pDC指针调用CDC类的函数进行绘图。

假使需要在视图窗口以外的窗口(譬如对话框)中绘制图形,就需要调用窗口类的WM_PAINT消息处理函数OnPaint来绘制或重画窗口,该函数中必需生成设备描述表类CPaintDC对象才能绘图,其代码例如如下:

voidCTestDialog::OnPaint(){//DevicecontextforpaintingCPaintDCpdc(this);//用户在此添加代码。}

对于在OnDraw和OnPaint之外的函数中绘制图形,必需生成设备描述表类CClientDC对象才能绘图,其代码例如如下:

voidCTestView::FunctionName(){//DevicecontextforpaintingCClientDCpdc(this);//用户在此添加代码。}

CWindowDC类的引用方法与CClientDC类似,“CWindowDCpdc(this);〞。只是其绘

4

图控制区为整个窗口区域,既包括客户区,也包括非客户区。

4.1.5、几种常用的图形数据结构和类

绘图程序中常用到的几种Windows的结构类型:POINT、RECT、SIZE。以及在MFC中与之对应的类:CPoint、CRect、CSize。

?点POINT数据结构:

typedefstructtagPOINT{

LONGx;LONGy;}POINT;

其中x、y表示一个点的坐标值。?矩形RECT数据结构:

typedefstructtagRECT{

LONGleft;LONGtop;LONGright;LONGbottom;}RECT;

其中left、top表示矩形左上角的x、y坐标值,right、bottom表示矩形右下角的x、y坐标值。

?表示矩形高宽的SIZE数据结构:

typedefstructtagSIZE{

intcx;intcy;}SIZE;

其中cx、cy表示矩形的宽度、高度值。

?CPoint类与POINT数据结构类似,它还包含了用来处理CPoint类和POINT结

构类型数据的成员函数。CPoint类的对象可以用在任何使用POINT结构数据的地方。CPoint类与SIZE结构和CSize类可以相互使用,由于它们的数据结构是一样的。

CPoint类是由POINT结构派生出的类,因此POINT结构的成员变量x、y也是CRect类的成员变量。

5

CPoint类的构造函数的形式如下:

CPoint();

CPoint(intinitX,intinitY);CPoint(POINTinitPt);CPoint(SIZEinitSize);

CPoint(DWORDdwPoint);//x坐标值放在dwPoint的低16位,y坐标

值放在dwPoint的高16位CPoint类重载的运算符有:==、!=、+=、-=、-、+等。

?CRect类与RECT数据结构类似,它还包含了用来处理CRect类和RECT结构

类型数据的成员函数。CRect类的对象可以用在任何使用RECT结构、LPCRECT和LPRECT数据的地方。CRect类与SIZE结构和CSIZE类可以相互使用,由于它们的数据结构是一样的。

CRect类是由RECT结构派生出的类,因此RECT结构的成员变量left、top、right、bottom也是CRect类的成员变量。CRect类的构造函数的形式如下:

CRect();

CRect(intleft,inttop,intright,intbottom);CRect(constRECTCRect(LPCRECTlpSrcRect);

CRect(POINTpoint,SIZEsize);//给出矩形左上角点point和矩形的

宽高值size)CRect(POINTtopLeft,POINTbottomRight);

CRect类重载的运算符:=、==、!=、+=、-=、

6

CSize(intinitCX,intinitCY);CSize(SIZEinitSize);CSize(POINTinitPt);

CSize(DWORDdwSize);//cx值放在dwPoint的低16位,cy值放

在dwPoint的高16位)。CSize类重载的运算符有:==、!=、+=、-=、-、+等。下面举例说明这些数据类型的使用方法:

CPointp1(300,300),p2;//定义两个点p1、p2,并初始化p1点CRectr1(CPoint(0,0),CPoint(100,100)),r2;//定义两个矩形r1、r2CSizes(100,100);//定义一个CSize对象s,并对其初始化p2=p1-CSize(50,50);//p2为(250,250)

r2=r1+s;//r2为(100,100)-(200,200),是平移矩形r1的结果r2=r1+p1;//r2为(300,300)-(400,400),是平移矩形r1的结果r2|=r1;//r2为(0,0)-(400,400),是r1和r2的轮廓矩形r2=CRect(20,20,200,200);//r2为(20,20)-(200,200)

r2//r2为(20,20)-(100,100),是r1和r2重叠的矩形

7

4.2、屏幕坐标系映射模式

在Windows环境中,所有的图形和文本输出的位置都对应于坐标系。图形和文本的坐标系是一致的。GDI支持两种坐标系,即设备坐标系和规律坐标系。

4.2.1、设备坐标系与规律坐标系

1.设备坐标系

设备坐标系是指具体的物理设备的坐标系,它是以像素作为坐标单位,默认的坐标系原点在绘图区域的左上角,X轴向右为正,Y轴向下为正。

设备坐标系又有三种独立的坐标系:屏幕坐标系、窗口坐标系、客户区坐标系,如图4-2所示。关于窗口和客户区的定义见图4-1。大多数应用程序的绘图区域是客户区,经常使用的是客户区坐标系。以后如不特别声明,称设备坐标系时均指客户区坐标系。

Y1图4-2设备坐标系Y2窗口坐标系客户区坐标系Y3X3屏幕坐标系X2X12.规律坐标系

规律坐标系是不考虑具体物理设备的一个统一的坐标系。图形的绘制是在以规律坐标系为基础的虚拟窗口(Window)中进行的,Windows能够通过映射模式将规律坐标系转化成设备坐标系,并将图形显示在视口(Viewport)中。Windows通过规律坐标系实现了与设备描述表的联系。

8

4.2.2、理解窗口与视口

要实现屏幕绘图,必需确凿理解Windows的绘图机制。Windows在绘图时,并不是把图形直接绘制到屏幕上,而是以规律坐标系将图形绘制到虚拟的窗口(Window)中,而当前的设备(如屏幕上的窗口客户区、打印机等)显示出来的只是虚拟窗口的一部分,当前设备显示图形的区域被称作为视口(Viewport),如图4-3所示。

必需正确理解视口和窗口的概念,否则对不同映射模式下规律坐标系与设备坐标系的相互关系很难把握,并且也不会充分地实现Windows的绘图功能。绝大多数绘图函数都使用规律坐标系。

OlYlOdXd设备显示图形的区域——视口。设备坐标系Yd虚拟的绘图区域——虚拟窗口规律坐标系图4-3窗口和视口

Xl4.2.3、窗口和视口坐标系位置的对应设置

窗口和视口的位置对应关系是通过设置它们对应的基准点实现的,默认的基准点都是(0,0),即虚拟绘图窗口中规律坐标系的(0,0)点映射到显示视口中设备坐标系的(0,0)点,规律坐标系坐标轴的方向和单位由屏幕映射模式确定。

窗口基准点的设置可以通过调用CDC::SetWindowOrg函数实现。函数定义如下:

CPointSetWindowOrg(intx,inty);CPointSetWindowOrg(POINTpoint);

参数(x,y)或point是以规律坐标值给定的窗口基准点。函数的返回值是一个CPoint对象,为原基准点(即设置前窗口的基准点),也是规律坐标值。

视口基准点的设置可以通过调用CDC::SetViewportOrg函数实现。函数定义如下:

virtualCPointSetViewportOrg(intx,inty);

9

virtualCPointSetViewportOrg(POINTpoint);

参数(x,y)或point是以设备坐标值给定的视口基准点,其值必需在设备坐标系的有效取值范围之内。函数的返回值是一个CPoint对象,为原基准点(即设置前视口的基准点),也是设备坐标值。

OlYLYlOdXD设备坐标系YDXdYd规律坐标系XL

图4-4窗口和视口的位置对应

Xl例如,假使设定规律坐标系为笛卡儿直角坐标系(Y轴向上),且一个像素等于n个规律坐标单位。执行下面的基准点设置语句:

SetWindowOrg(XL,YL);SetViewportOrg(XD,YD);

由图4-4可得到规律坐标(x,y)与设备坐标(X,Y)的转换关系为:X=x/n-(XL/n-XD);Y=(YL/n+YD)–y/n;

4.2.4、坐标映射模式

规律坐标系映射模式的设置函数为CDC::SetMapMode,其格式为:

virtualintSetMapMode(intnMapMode);

参数nMapMode为映射模式的值。函数的返回值为前一个映射模式的值。

10

1.MM_TEXT映射模式

MM_TEXT为系统缺省的映射模式,它的坐标单位被映射到了像素,X轴向右为正,Y轴向下为正。

下面的代码把坐标映射模式设为MM_TEXT方式,并且把窗口的原点设在视口的(300,300)点处,亦即绘图的规律坐标系原点在视口的(300,300)点处。

DC.SetMapMode(MM_TEXT);DC.SetViewportOrg(CPoint(300,300));

2.规律坐标单位固定的映射模式

此类映射模式的规律坐标单位是固定的,X轴向右为正,Y轴向上为正。此类映射模式有5种,列表如下:

映射模式MM_LOENGLISHMM_HIENGLISHMM_LOMETRICMM_HIMETRICMM_TWIPS规律坐标单位0.01英寸0.001英寸0.1毫米0.01毫米1/1440英寸MM_TWIPS映射模式往往用于打印机,一个“twip〞单位相当于1/20磅(1磅等于1/72英寸)。

3.规律坐标比例可变的映射模式

在这种映射模式下面,不但可以改变坐标单位的比例因子,还可以改变坐标轴的方向。借助于这样的映射方式,当用户改变窗口的尺寸的时候,绘制的图形的大小也可以根据比例发生相应的变化;当用户翻转某个轴方向的时候,绘制的图像也可以进行翻转;当用户对视窗进行滚动操作时,图像也可以进行滚动。

这样的映射方式有以下两种:

11

映射模式MM_ISOTROPIC规律坐标单位比例可任意调理,但X和Y轴向的坐标单位相等MM_ANISOTROPIC可任意调理,且X和Y轴向的坐标单位可不相等在MM_ISOTROPIC模式下,纵横的比例为1:1,换句话说,无论比例因子如何变化,画出的图形不会改变自己的形状。但是在MM_ANISOTROPIC模式下,X和Y轴向单位的比例因子可以独立地变化,亦即图形的形状可以发生变化。

这种映射模式下规律坐标单位比例和坐标轴方向的改变,是通过在窗口和视口中各设置一个矩形进行对应来实现的,两个矩形高宽幅度的比值确定了坐标系的换算关系。具体的操作是由两个函数CDC::SetWindowExt和CDC::SetViewportExt进行的,这两个函数只有在MM_ISOTROPIC和MM_ANISOTROPIC映射模式下才有效。

CDC::SetWindowExt函数定义如下:

virtualCSizeSetWindowExt(intcx,intcy);virtualCSizeSetWindowExt(SIZEsize);

参数(cx,cy)或size是以规律坐标值给定的窗口中一个矩形的宽高值(即x和y方向的幅度值)。函数的返回值是一个CSize对象,为规律坐标值,是设定前窗口中一个矩形的高宽值。假使出错,返回的CSize对象的x和y值均为0。

CDC::SetViewportExt函数定义如下:

virtualCSizeSetViewportExt(intcx,intcy);virtualCSizeSetViewportExt(SIZEsize);

参数(cx,cy)或size是以设备坐标值给定的视口中一个矩形的宽高值(即x和y方向的幅度值)。函数的返回值是一个CSize对象,为设备坐标值,是设定前视口中一个矩形的高宽值。假使出错,返回的CSize对象的x和y值均为0。

假使要设定规律坐标系的Y轴向上为正,可将其中一个矩形的高度取为负值即可。在进行窗口和视口的矩形高宽幅度值的设定时,高宽值不表示窗口或视口的大小,其值的大小并不重要,重要的是两个矩形高宽幅度值的对应比例,由于它确定了规律坐标系与设备坐标系坐标值的换算比例。

注意:在MM_ISOTROPIC映射模式下,必需先设置窗口的幅度值(即先调用SetWindowExt函数),再设置视口的幅度值(即后调用SetViewportExt函数)。

分析下面这个程序:

voidCTestView::OnDraw(CDC*pDC)

12

{}

//TODO:adddrawcodefornativedatahere//以下为第一段代码:CRectclientRect;

GetClientRect(clientRect);

pDC->SetMapMode(MM_ANISOTROPIC);pDC->SetWindowExt(1000,1000);

pDC->SetViewportExt(clientRect.right,-clientRect.bottom);pDC->SetViewportOrg(clientRect.right/2,clientRect.bottom/2);pDC->Ellipse(CRect(-500,-500,500,500));//以下为其次段代码:

pDC->SetMapMode(MM_ISOTROPIC);pDC->SetWindowExt(1000,1000);

pDC->SetViewportExt(clientRect.right,-clientRect.bottom);pDC->SetViewportOrg(clientRect.right/2,clientRect.bottom/2);pDC->Ellipse(CRect(-500,-500,500,500));

第一段代码的功能是这样的:

1)由GetClientRect函数取得窗口客户区矩形的大小clientRect(设备坐标值),其左

上角为(0,0),右下角为(clientRect.right,clientRect.bottom),即右下角的坐标值是窗口客户区矩形的宽高幅度值;2)设定映射模式为MM_ANISOTROPIC,即规律坐标单位可任意调理,且X和Y

轴向的坐标单位可不相等;3)用SetWindowExt()函数设定窗口的宽高幅度为(1000,1000)规律坐标单位;4)用SetViewportExt()函数设定视口的宽高幅度为(clientRect.right,

-clientRect.bottom)设备坐标单位,其中Y值取负的作用是设定规律坐标系Y轴向上为正,此时可得规律坐标与设备坐标的换算比例;5)由SetViewportOrg()函数设定视口的中心点与规律坐标系原点对应;

6)执行绘图函数Ellipse,在(-500,-500,500,500)的矩形内绘制出一个半径为500的

椭圆(由于X、Y轴向比例不同,它看起来像椭圆),如图4-4所示。在其次段代码中将映射模式改变为MM_ISOTROPIC,其它语句与第一段代码一样,

结果将画出一个如图4-4中间所示的圆。在MM_ISOTROPIC映射方式下,规律坐标单位的比例以视口矩形宽(X轴向)、高(Y轴向)中的最小值来设定。

13

图4-4坐标单位比例可变映射模式下的图形

由此可以得出在MM_ISOTROPIC和MM_ANISOTROPIC映射模式下,规律坐标到设备坐标的计算公式:

设定:SX为X轴向的比例因子,SY为Y轴向的比例因子。

视口的矩形范围为(W视口,H视口),窗口的矩形范围为(W窗口,H窗口)规律坐标系原点(0,0)与设备坐标系中的(XO,YO)点对应。则轴向比例因子的计算公式为:

SX=W视口/W窗口SY=H视口/H窗口

则规律坐标(x,y)到设备坐标(X,Y)的计算公式为:

X=x*SX+XOY=y*SY+YO

4.2.5、设备坐标系与规律坐标系之间的转换

当设定了设备描述表的映射模式之后,就可以直接使用规律坐标作为其参数了,但是从WM_MOUSEMOVE消息所获得的鼠标的坐标值是设备坐标。大量其他的MFC库函数,只接受设备坐标。所以有时要利用CDC的LPtoDP和DPtoLP函数在规律坐标和设备坐标之间进行转换的工作。

voidLPtoDP(LPPOINTlpPoints);voidDPtoLP(LPPOINTlpPoints);

例如:Cpointp(100,100);//定义一个点p,其值为设备坐标(100,100)

14

pDC->DPtoLP(//将点实现从设备坐标转换成规律坐标可以认为CDC类的绝大多数成员函数是以规律坐标作为参数的。

特别注意:应以规律坐标的形式保存图形数据,否则用户对视窗进行滚动操作的时候,这个数据就不再有效了。

4.3、绘图工具类

MFC中定义了一些Windows的图形设备界面(GDI)对象类,即绘图工具类,它们是作图的笔、给图形涂色的画刷,以及字体、位图、区域和调色板等影响绘图的工具。前面讲的设备描述表对象可以选入这些绘图工具来完成指定的图形操作。

绘图工具类主要有:CGdiObject、CPen、CBrush、CFont、CRgn和CBitmap类等。其中CGdiObject类是CObject类的派生类,它是绘图工具类的基类。CGdiObject类为它的派生类提供了大部分操作,但不能直接建立一个CGdiObject类的对象。

画笔CPen用于绘制直线、矩形、圆等几何图形,其属性主要有:线宽、线型和色调等。画刷CBrush用于填充绘图区域,其属性有填充图案和色调。

在生成设备描述表类对象时,假使没有指定笔和画刷,那么默认笔为线宽1个像素的黑色实线;默认的画刷为单一白色图案,即图形内部填充白色。

对绘图工具的使用包括:创立、选择和使用后的释放等过程。CDC类提供了两个成员函数SelectStockObject和SelectObject来选择GDI绘图工具。

选择自己创立的新绘图工具后,程序就将使用该工具绘图,直到选择其它的工具为止。当绘图完成后,应当恢复绘图以前的旧绘图工具,并及时释放当前绘图工具,以释放其占用的内存空间。程序中的代码(以画笔为例)寻常如下所示:

CPen*pPen,*pOldPen;//定义两个画笔指针变量pPen=newCPen(PS_SOLID,1,RGB(255,0,0));//动态创立画笔(实线、线宽为1个单位、色调为红色)

pOldPen=(CPen*)pDC->SelectObject(pPen);//选入新画笔,保存旧画笔??//绘图工作pDC->SelectObject(pOldPen);//恢复旧画笔

deletepPen;//删除动态创立的画笔

4.3.1、选择GDI库存的绘图工具

调用CDC类的成员函数SelectStockObject选择GDI库存的绘图工具。其格式为:

15

virtualCGdiObject*SelectStockObject(intnIndex);其中参数nIndex的取值见下表:参数值BLACK_BRUSHGRAY_BRUSHLTGRAY_BRUSH库存绘图工具黑刷(Blackbrush)灰刷(Graybrush)淡灰刷(Lightgraybrush)白刷(Whitebrush)(系统默认值)空刷(Nullbrush)(无画刷填充)黑笔(Blackpen)(系统默认值)白笔(Whitepen)空笔(Nullpen)(即不画)DKGRAY_BRUSH深灰刷(Darkgraybrush)画刷WHITE_BRUSHNULL_BRUSH画BLACK_PENWHITE_PENHOLLOW_BRUSH空刷(Hollowbrush)(相当于NULL_BRUSH)笔NULL_PEN假使函数调用成功,其返回值为一指向被替换的CGdiObject绘图工具对象的指针

(其实际所指的对象可能是CPen、CBrush或CFont)。假使函数调用失败,返回NULL。

下面的程序分别调用各种GDI库存绘图工具进行绘图,图形如图4-5所示。voidCTestView::OnDraw(CDC*pDC)

{//TODO:adddrawcodefornativedatahereCPointp(180,120);pDC->SelectStockObject(LTGRAY_BRUSH);pDC->Ellipse(p.x-170,p.y-110,p.x+170,p.y+110);pDC->SelectStockObject(BLACK_BRUSH);pDC->Rectangle(p.x-120,p.y-70,p.x-20,p.y-20);pDC->SelectStockObject(DKGRAY_BRUSH);pDC->Rectangle(p.x+20,p.y-70,p.x+120,p.y-20);pDC->SelectStockObject(GRAY_BRUSH);pDC->Rectangle(p.x+20,p.y+20,p.x+120,p.y+70);pDC->SelectStockObject(WHITE_BRUSH);pDC->Rectangle(p.x-120,p.y+20,p.x-20,p.y+70);pDC->SelectStockObject(HOLLOW_BRUSH);pDC->SelectStockObject(WHITE_PEN);pDC->Rectangle(p.x-70,p.y-50,p.x+70,p.y-5);pDC->SelectStockObject(BLACK_PEN);pDC->Rectangle(p.x-70,p.y+5,p.x+70,p.y+50);

16

}

图4-5各种GDI库存绘图工具例如

4.3.2、自定义绘图工具的创立和使用

1.CPen绘图工具

CPen画笔主要用于绘制直线、矩形、圆等几何图形。CPen的构造函数如下:

CPen(intnPenStyle,intnWidth,COLORREFcrColor);

其中参数nPenStyle为线型、nWidth为线宽、crColor为色调。其创立画笔的成员函数CreatePen的参数与构造函数一致。

建立CPen画笔的方法有:

1)定义一个CPen对象,并用其成员函数CreatePen构造画笔

CPenp;

p.CreatePen(PS_SOLID,1,RGB(255,0,0));

创立了一个CPen画笔对象p,并把这个画笔设置成实线、线宽为1个坐标单位、色调为红色。

2)使用CPen构造函数建立一个画笔对象,并定义其参数

CPenp(PS_SOLID,1,RGB(255,0,0));

一次性的创立了一个同样的画笔对象p,其参数设置为红色实线、线宽1个单位。

17

3)用CPen指针对象的形式动态创立一个画笔

CPen*pPen;

pPen=newCPen(PS_SOLID,1,RGB(255,0,0));

pPen指针指向一个由new建立的CPen画笔对象,并把这个画笔设置成实线、线宽1个单位、色调为红色。

在一个函数中假使需要屡屡构造一个画笔时,应当采用这种方法。但应特别强调的是,使用完毕后必需释放给画笔分派的内存空间,即删除画笔:

deletepPen;

画笔的线宽nWidth的取值以规律坐标为单位,假使nWidth=0,则忽略坐标映射模式,线宽为1个像素。

画笔的色调参数crColor的数据类型为COLORREF。画笔的色调只能是Windows中常用的16种纯色(见4.4.1中的内容),假使定义的色调不是纯色,则在画线时会用最接近的纯色来代替。

画笔的线型nPenStyle的选择如下表:

线型值PS_SOLIDPS_DASHPS_DOTPS_DASHDOTPS_DASHDOTDOTPS_NULLPS_INSIDEFRAMEPS_USERSTYLE

注意,线型PS_DASH、PS_DOT、PS_DASHDOT和PS_DASHDOTDOT只有在画笔宽度为1个像素时才能使用。假使线宽nWidth值大于1个像素,则画出给定宽度的实线(PS_SOLID)。

图4-6为选择不同线型绘制图形的例如,其OnDraw函数程序代码如下:voidCTestView::OnDraw(CDC*pDC){

线型空笔用户自定义笔//TODO:adddrawcodefornativedatahereCPen*pPen,*pOldPen;CPointp1(15,15),p2(220,220);

18

}

intps[6]={};inti;

pDC->SetMapMode(MM_TEXT);pDC->SetViewportOrg(0,0);

for(i=0;iSetViewportOrg(280,0);p1=CPoint(15,15);p2=CPoint(220,220);for(i=0;iSelectObject(pPen);pDC->Rectangle(CRect(p1,p2));p1.Offset(12,12);p2.Offset(-12,-12);

pDC->SelectObject(pOldPen);deletepPen;

pPen=newCPen(ps[i],0,RGB(0,0,0));//线宽为0,表示线宽为1个像素pOldPen=(CPen*)pDC->SelectObject(pPen);pDC->Rectangle(CRect(p1,p2));p1.Offset(12,12);p2.Offset(-12,-12);

pDC->SelectObject(pOldPen);deletepPen;

PS_SOLID,PS_DASH,PS_DOT,

PS_DASHDOT,PS_DASHDOTDOT,PS_INSIDEFRAME

在该程序中,为了说明线宽对线型的影响,使用不同的线宽绘制同一个图形两次,其次次绘制时使用函数SetViewportOrg(280,0)将视口左移280个像素。

19

图4-6选择不同线型绘制图形例如

假使需要自定义线型,可以使用CPen重载的另一个构造函数(重载的成员函数CreatePen的参数与它一致):

CPen(intnPenStyle,intnWidth,constLOGBRUSH*pLogBrush,

intnStyleCount=0,constDWORD*lpStyle=NULL);其中参数:nPenStyle取值为PS_USERSTYLE。

nWidth取值为1个像素。

pLogBrush为指向LOGBRUSH结构类型数据的指针,该参数设置笔刷

的样式、色调和图案。lpStyle只有在nPenStyle取值为PS_USERSTYLE才有意义,否则lpStyle

必需为NULL。lpStyle为一个DWORD类型的数组,用来设置线型的具体参数,数组中第一个数据表示线段长(像素数),其次个数表示空隙长(像素数),以后各数以此类推。nStyleCount也只有在nPenStyle取值为PS_USERSTYLE才有意义,否则,nStyleCount必需为0。nStyleCount表示数组lpStyle中数据的个数。

图4-7是用自定义线型(点划线和虚线)来创立画笔绘制的图形。该例如的OnDraw

函数的代码如下:

voidCTestView::OnDraw(CDC*pDC){//TODO:adddrawcodefornativedatahere

20

}

CPen*pPen,*pOldPen;CRectr(50,50,370,370);

pPen=newCPen(PS_SOLID,3,RGB(0,0,0));//创立线宽为3的实线画笔pOldPen=(CPen*)pDC->SelectObject(pPen);//选入新画笔,保存旧画笔pDC->Ellipse(r);//绘制粗实线圆pDC->SelectObject(pOldPen);//恢复旧画笔

deletepPen;//删除动态创立的画笔

DWORDStyle[4];//定义存放线型长度的数组LOGBRUSHb;b.lbStyle=BS_SOLID;//设置实心笔刷b.lbColor=RGB(0,0,0);//设置笔刷色调为黑色b.lbHatch=0;//设置为实心笔刷时,图案值无效Style[0]=5;Style[1]=1;

//设置虚线的样式,2个数为一单元,长划为5、空隙为1

pPen=newCPen(PS_USERSTYLE,1,//动态创立画笔pOldPen=(CPen*)pDC->SelectObject(pPen);//选入新画笔,保存旧画笔r.DeflateRect(65,65);//将矩形r高宽各缩小65个单位pDC->Rectangle(r);//绘制矩形r

r.InflateRect(65,65);//将矩形r高宽各放大65个单位pDC->SelectObject(pOldPen);//恢复旧画笔

deletepPen;//删除动态创立的画笔

Style[0]=20;Style[1]=Style[2]=Style[3]=2;

//设置点划线的样式,4个数为一单元,长划20、空隙2、短划2、空隙2pPen=newCPen(PS_USERSTYLE,1,//动态创立画笔

pOldPen=(CPen*)pDC->SelectObject(pPen);//选入新画笔,保存旧画笔CPoints1,s2;

s1.x=s2.x=(r.left+r.right)/2;s1.y=r.bottom+20;s2.y=r.top-20;

pDC->MoveTo(s1);pDC->LineTo(s2);//绘制竖直点划线s1.x=r.left-20;s2.x=r.right+20;

s2.y=s1.y=(r.top+r.bottom)/2;

pDC->MoveTo(s1);pDC->LineTo(s2);//绘制水平点划线pDC->SelectObject(pOldPen);//恢复旧画笔

deletepPen;//删除动态创立的画笔

21

图4-7用自定义线型创立画笔的例如

创立画笔后,必需调用CDC::SelectObject函数将其选入当前的设备描述表对象,才能在绘图中使用。调用该函数的同时必需保存以前的画笔对象。

SelectObject是一个重载函数,各种绘图工具均由它选入设备描述表对象中,函数的原型说明如下:

CPen*SelectObject(CPen*pPen);

CBrush*SelectObject(CBrush*pBrush);virtualCFont*SelectObject(CFont*pFont);CBitmap*SelectObject(CBitmap*pBitmap);

2.CBrush绘图工具

CBrush画刷主要用颜色和图案来填充指定的区域。画刷工具的使用与画笔工具类似。

CBrush(COLORREFcrColor);

CBrush(intnIndex,COLORREFcrColor);CBrush(CBitmap*pBitmap);

画刷的色调参数crColor的取值与初始化画笔的色调不同,不必是纯色,可以是任意的色调值,假使不是纯色,Windows会自动产生配色。

22

A、建立实心画刷

这种画刷以定义的色调实心填充区域。建立该种画刷的方法有:

1)定义一个CBrush对象,并用其成员函数CreateSolidBrush构造画刷

CBrushb;

b.CreateSolidBrush(RGB(255,0,0));创立了一个红色的CBrush对象b。

2)使用CBrush构造函数,一次性的构造一个红色画刷对象b

CBrushb(RGB(255,0,0));

3)用画刷指针动态创立一个红色画刷

CBrush*pBrush;

pBrush=newCBrush(RGB(255,0,0));

pBrush指针指向一个由new建立的CBrush对象。在一个函数中假使需要屡屡构造一个画刷时,应当采用这种方法。但应特别强调的是,使用完毕后必需释放给画刷分派的内存空间,即删除画刷:

deletepBrush;

B、建立图案画刷

这种画刷以定义的色调和图案,在指定区域中填充阴影图案。构造方法与实心画刷一致:

1)用成员函数CreateHatchBrush构造画刷

CBrushb;

b.CreateHatchBrush(HS_FDIAGONAL,RGB(255,0,0));创立了一个红色45°斜线图案的CBrush对象b。图案样式nIndex的取值见下表:

23

图案值图案的形式图案HS_HORIZONTAL水平阴影线HS_VERTICALHS_CROSS竖直阴影线水平与竖直交织阴影线HS_BDIAGONAL从左下到右上的45°斜线HS_FDIAGONALHS_DIAGCROSS2)使用CBrush构造函数,一次性的构造一个画刷对象b

CBrushb(HS_FDIAGONAL,RGB(255,0,0));3)用画刷指针动态创立一个画刷

CBrush*pBrush;

pBrush=newCBrush(HS_FDIAGONAL,RGB(255,0,0));

从左上到右下的45°斜线45°交织线pBrush指针指向一个由new建立的CBrush对象。在一个函数中假使需要屡屡构造一个画刷时,应当采用这种方法。但应特别强调的是,使用完毕后必需释放画刷的内存空间,即删除画刷:

deletepBrush;

在设备描述表对象中选入画刷的操作与选入画笔一致,也是调用CDC::SelectObject重载函数进行选入。同样,调用该函数的同时必需保存以前的画刷对象。下面的程序段是同时对画笔和画刷进行创立、选择和使用后释放过程的例如。

??

CPen*pPen,*pOldPen;

CBrush*pBrush,*pOldBrush;//定义两个画刷指针变量pPen=newCPen(PS_SOLID,1,RGB(0,0,0));pOldPen=(CPen*)pDC->SelectObject(pPen);pBrush=newCBrush(HS_FDIAGONAL,RGB(0,0,0));

24

//动态创立画刷(从左上到右下的45°斜线、色调为黑色)

pOldBrush=(CBrush*)pDC->SelectObject(pBrush);//选入新画刷,保存旧画刷??//绘图工作pDC->SelectObject(pOldPen);

pDC->SelectObject(pOldBrush);//恢复旧画刷??

deletepPen;

deletepBrush;//删除动态创立的画刷

图4-8是用不同的图案画刷绘制的柱状图。该例如的OnDraw函数的代码如下:voidCTestView::OnDraw(CDC*pDC){//TODO:adddrawcodefornativedatahereCPen*pPen,*pOldPen;CBrush*pBrush,*pOldBrush;intbs[6]={HS_CROSS,HS_HORIZONTAL,HS_BDIAGONAL,HS_FDIAGONAL,HS_VERTICAL,HS_DIAGCROSS};CRectr(0,0,50,300);CPointp1(40,20),p2(40,300);pPen=newCPen(PS_SOLID,1,RGB(0,0,0));//动态创立画笔pOldPen=(CPen*)pDC->SelectObject(pPen);pDC->MoveTo(p1);pDC->LineTo(p2);//绘制直线p2=CPoint(450,300);pDC->LineTo(p2);srand((unsigned)time(NULL));//用系统的时间设置随机数发生器inti;for(i=0;iSelectObject(pBrush);r.top=(int)(250*rand()/(float)(RAND_MAX));//随机产生矩形上边的Y坐标r+=CPoint(52,0);

25

}

pDC->SetBrushOrg(r.TopLeft());//设置画刷的原点pDC->Rectangle(r);pDC->SelectObject(pOldBrush);//恢复旧画刷deletepBrush;//删除动态创立的画刷}

pDC->SelectObject(pOldPen);

deletepPen;//删除动态创立的画笔

图4-8柱状图

C、位图填充的画刷

函数CBrush(CBitmap*pBitmap)和CreatePatternBrush(CBitmap*pBitmap)用来构造一个画刷,这个画刷用位图图像文件填充指定的区域。参数pBitmap是一个位图对象的指针。

4.4、设置绘图属性4.4.1、颜色参数的设置

Windows的图形设备界面(GDI)采用的是“硬件独立〞的颜色接口,即应用程序提供的是绝对颜色代码,GDI会产生适合的颜色映射到显示器硬件上。

颜色代码的数据类型是32-bit的COLORREF类型,这种类型的数据包含了三个8-bit

26

的颜色值,分别对应红、绿、蓝三色,每一个色调的取值范围是0-255。GDI绘图函数中的颜色参数一般为COLORREF类型。

定义颜色代码数值最简单的方法是通过使用Win32的RGB宏指定颜色,其格式如下:

COLORREFRGB(BYTEbRed,BYTEbGreen,BYTEbBlue);

其中参数bRed、bGreen、bBlue为三个8-bit的BYTE类型数据,表示红绿蓝三色在0-255的取值。RGB宏的结果为COLORREF类型的颜色值。

Windows中寻常用到的16种纯色为:

颜色黑Black蓝Blue深蓝Darkblue绿Green深绿Darkgreen淡青Cyan深青Darkcyan红Red深红Darkred淡洋红Magenta深洋红Darkmagenta黄Yellow深黄Darkyellow深灰Darkgray淡灰Lightgray白White

在程序中为了便于设置色调,可在绘图窗口类(例如视窗或对话框)添加一个访问类型为public的新成员数据m_Colors[16],其类型为staticconstCOLORREF,是一个静态常量数组。并在视窗类实现文件的顶部定义该常量数组的值,其定义位置在窗口类的构造函数和析构函数的定义代码之前,该数组的定义如下:

constCOLORREFCTestView::m_Colors[16]={

RGB(0,0,0),//0—黑Black

27

Red0000000255128255128255128128192255Green0002551282551280000255128128192255Blue0255128002551280025512800128192255RGB(0,0,128),//1—深蓝DarkblueRGB(0,128,0),//2—深绿DarkgreenRGB(0,128,128),//3—深青DarkcyanRGB(128,0,0),//4—深红DarkredRGB(128,0,128),//5—深洋红DarkmagentaRGB(128,128,0),//6—深黄DarkyellowRGB(192,192,192),//7—淡灰LightgrayRGB(128,128,128),//8—深灰DarkgrayRGB(0,0,255),//9—蓝BlueRGB(0,255,0),//10—绿GreenRGB(0,255,255),//11—淡青CyanRGB(255,0,0),//12—红RedRGB(255,0,255),//13—淡洋红MagentaRGB(255,255,0),//14—黄YellowRGB(255,255,255)//15—白White};

该数组为16种纯色的色调码数组,其中颜色的排列尽可能地接近了DOS屏幕绘图中的色调顺序。以后在程序中可直接使用该数组值,省去了颜色值的换算。

如图4-9所示,用Windows的16种纯色画出逐渐缩小的16个矩形,第一个矩形为(50,10,400,360),后一个矩形高宽比前一个缩小10个象素。

图4-9用16种纯色画出的矩形

在绘图视窗窗口类中添加一个前述的成员数据m_Colors[16],并在视窗类实现文件

28

中定义该数组的值为色调码。OnDraw函数中的代码如下:

voidCTestView::OnDraw(CDC*pDC){//TODO:adddrawcodefornativedatahere}

在程序中也可以使用Windows系统中预定义的颜色值,要得到这些颜色可以使用函数GetSysColor,它的原型如下:

DWORDGetSysColor(intnIndex);

函数的返回值是32-bit的DWORD类型色调值,与COLORREF类型一致。参数nIndex为系统颜色的符号常量,其取值如下表:

符号常量COLOR_3DDKSHADOWCOLOR_3DFACE或COLOR_BTNFACECOLOR_3DHILIGHT或OLOR_3DHIGHLIGHTCOLOR_3DLIGHTCPen*pPen,*pOldPen;inti;

CRectr(50,10,400,360);for(i=0;iSelectObject(pPen);//选入新画笔,保存旧画笔r.DeflateRect(10,10);//矩形r高宽各缩小10个象素pDC->Rectangle(r);//绘制矩形rpDC->SelectObject(pOldPen);//恢复旧画笔

deletepPen;//删除创立的画笔

含义立体显示元件的暗阴影颜色立体显示元件的表面颜色立体元件高亮显示时的颜色立体元件亮色显示时的颜色COLOR_3DSHADOW或COLOR_BTNSHADOW立体显示元件的阴影颜色COLOR_ACTIVEBORDERCOLOR_ACTIVECAPTIONCOLOR_APPWORKSPACECOLOR_BACKGROUND或COLOR_DESKTOP

29

活动窗口边界颜色活动窗口标题条颜色(渐变效果,取左边色)多文档程序的背风景Windows桌面的颜色COLOR_BTNTEXTCOLOR_CAPTIONTEXTCOLOR_GRADIENTACTIVECAPTIONCOLOR_GRAYTEXTCOLOR_HIGHLIGHTCOLOR_HIGHLIGHTTEXTCOLOR_INACTIVEBORDERCOLOR_INACTIVECAPTIONCOLOR_INACTIVECAPTIONTEXTCOLOR_INFOBKCOLOR_INFOTEXTCOLOR_MENUCOLOR_MENUTEXTCOLOR_SCROLLBARCOLOR_WINDOWCOLOR_WINDOWFRAMECOLOR_WINDOWTEXT按钮上文本的颜色窗口栏文本的颜色活动窗口渐变效果标题条右边颜色灰色显示(无效)文本的颜色选定项的背风景选定项的文本颜色非活动窗口边界的颜色非活动窗口标题条的颜色非活动窗口标题条中文本的颜色工具提醒的背景颜色工具提醒文本的颜色菜单栏的背风景菜单栏的文本颜色窗口滚动条的颜色.窗口背景的颜色窗口边框的颜色窗口文本的颜色

4.4.2、图形的背风景和背景方式

使用CDC成员函数SetBkColor可以设置线型(非实线)空隙、画刷图案间隙和文本输出的背风景。其格式如下:

COLORREFSetBkColor(COLORREFcrColor);

其中crColor为指定的颜色值。函数的返回值为前一次的背风景。

使用CDC成员函数SetBkMode可以设置线型空隙、画刷图案间隙和文本输出的背景方式。其格式如下:

intSetBkMode(intnBkMode);

其中nBkMode为背景方式的参数,它的值可为下面两个值之一:

OPAQUE——表示不透明的,即线型空隙、画刷图案间隙和文本输出的背景均绘出背风景。

TRANSPARENT——表示图形是透明的,背风景不起作用。函数的返回值为前一次的背景方式。

30

函数SetBkColor和SetBkMode主要影响Chord、Ellipse、Pie、Polygon、Rectangle、TextOut等成员函数的绘制效果。

图4-10是设置了图形背风景和背景方式绘制的图形,左右两边的图形是通过改变视口位置把同一个图形绘制两次,两次绘制的不同仅是选用了不同的图形背景方式,左边的为不透明方式,右边的为透明方式。该例如的OnDraw函数的代码如下:

图4-10图形背风景和背景方式的例如

voidCTestView::OnDraw(CDC*pDC){//TODO:adddrawcodefornativedatahereCPen*pPen,*pOldPen;CBrush*pBrush,*pOldBrush;CRectr(30,30,250,180);pPen=newCPen(PS_SOLID,1,RGB(0,0,0));pOldPen=(CPen*)pDC->SelectObject(pPen);pBrush=newCBrush(HS_FDIAGONAL,RGB(0,0,0));pOldBrush=(CBrush*)pDC->SelectObject(pBrush);pDC->SetViewportOrg(0,0);//设置视口基准点为(0,0)pDC->RoundRect(r,CPoint(50,50));//绘制圆角矩形pDC->SetViewportOrg(280,0);//设置视口基准点为(280,0)pDC->RoundRect(r,CPoint(50,50));//再绘制圆角矩形

deletepBrush;pBrush=newCBrush(HS_BDIAGONAL,RGB(0,0,0));pDC->SelectObject(pBrush);pDC->SetBkColor(RGB(64,192,128));//设置图形背风景

31

}

r.DeflateRect(30,30);//缩小矩形r

pDC->SetViewportOrg(0,0);//设置视口基准点为(0,0)

pDC->SetBkMode(OPAQUE);//设置图形背景方式为不透明的pDC->Rectangle(r);//绘制矩形r

pDC->SetViewportOrg(280,0);//设置视口基准点为(280,0)pDC->SetBkMode(TRANSPARENT);//设置图形背景方式为透明的pDC->Rectangle(r);//再绘制矩形rpDC->SelectObject(pOldBrush);deletepBrush;

pDC->SelectObject(pOldPen);deletepPen;

4.4.3、绘图方式

绘图方式的设置只适用于光栅扫描设备(显示器)。

使用CDC成员函数SetROP2可以设置画笔和画刷在绘图时与屏幕上已显示图形的组合方式,即设置屏幕中图形经过的像素点应显示的颜色值。其格式如下:

intSetROP2(intnDrawMode);

函数的返回值是上一次的绘图方式。参数nDrawMode的取值见下表:

符号常量R2_BLACKR2_WHITER2_NOPR2_NOTR2_COPYPENR2_NOTCOPYPEN总为黑色总为白色像素的颜色不变像素的颜色为屏幕的反转色画笔的颜色具有画笔的反转色含义R2_MERGEPENNOT像素的颜色是:画笔与屏幕反转色的“或〞运算结果R2_MASKPENNOT像素的颜色是:画笔与屏幕反转色的“与〞运算结果R2_MERGENOTPEN像素的颜色是:画笔反转色与屏幕的“或〞运算结果R2_MASKNOTPEN

像素的颜色是:画笔反转色与屏幕的“与〞运算结果32

R2_MERGEPEN像素的颜色是:画笔与屏幕的“或〞运算结果R2_NOTMERGEPEN像素的颜色是:画笔与屏幕“或〞运算结果的反转色R2_MASKPENR2_NOTMASKPENR2_XORPENR2_NOTXORPEN图4-11是设置了不同绘图方式的图形例如,为了说明不同绘图方式对图形的影响,背景图形为四个不同颜色的矩形。中间四个逐渐缩小的矩形是由在不同绘图方式下的同一画笔画出的。该例如的OnDraw函数的代码如下:

像素的颜色是:画笔与屏幕的“与〞运算结果像素的颜色是:画笔与屏幕“与〞运算结果的反转色像素的颜色是:画笔与屏幕的“异或〞运算结果像素的颜色是:画笔与屏幕“异或〞运算结果的反转色

图4-11不同绘图方式的例如

温馨提示

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

评论

0/150

提交评论