1Lesson07-08图形设备接口Windows系统具有丰富的图形界面。Windows系统提供许多函数来实现绘图的要求。而图形设备接口(GraphicsDeviceInterface,简写为GDI)就可看作是这些函数的集合。GDI表示的是一个抽象的接口。通过该接口可以实现对图形的颜色、线条的粗细等属性的控制(甚至包括输出文字在内)。应用程序可以通过调用这些GDI函数和硬件打交道,而不必知道到底是哪个厂家生产的硬件,从而实现了设备无关性。Windows系统本身也使用GDI来绘制用户界面的各个部分。一、设备环境1.设备环境Windows默认使用客户区坐标系,其原点在窗口客户区的左上角,X轴的正方向指向右边,Y轴的正方向指向下边。当应用程序并没有设置颜色、字体等时,系统使用默认的设置。这些默认的设置保存在设备环境中。如果没有设备环境,则每输出一个字符串(调用一次TextOut函数),就需要把字体和颜色也作为参数传递给TextOut函数,而且这样的参数有很多。为了避免这样的麻烦,Windows就把这些可能会重复的参数放在了设备环境中,这样每次只需要多传入一个设备环境的指针就可以了,大大减少了重复工作。设备环境(DeviceContext,缩写为DC,有时译为设备上下文,也称设备描述表)是一种包含各种绘图属性(如字体、颜色等等)和方法(即各种绘图函数)的数据结构(或者集合)。它不仅可以绘制各种图形,而且还可以确定在应用窗口中绘制图形的方式,即确定绘图混和模式和映射模式。用户在绘图之前,必须获取绘图窗口区域的一个设备环境DC,才能进行GDI函数的调用,执行适合于设备环境DC的命令(就像OnDraw函数中的pDC指针)。DC中除了提供绘图的函数(如:TextOut)以外,还会提供给用户改变绘图属性的函数,如颜色。Windows的设备环境是GDI的关键元素,它代表了不同的物理设备。分为4种类型:显示型、打印机型、内存型和信息型。每种类型的设备环境都有各自的特定用途,见下表:设备环境的类型和用途设备环境用途显示器型支持视频显示器上的绘图操作打印机型支持打印机和绘图仪上的绘图操作内存型支持位图上的绘图操作信息型支持设备数据的访问2.MFC中的设备环境类在MFC类库中,设备环境被CDC类封装了起来,而CDC类下面又有4个派生类,各有特点,并可以完成不同的功能,如下所示:CMetaFileDC专门用于Windows图元文件,剩下的三种DC类之间存在差别:2CDC类的派生类派生类名称说明CClientDC说明一个客户区设备环境,提供对窗口客户区域的图形访问。在窗口中画图时可使用这种DC,但对WM_PAINT消息除外CWindowDC可以提供在整个窗口(包括客户区和非客户区)中画图的设备环境CPaintDC这是创建响应WM_PAINT消息的设备环境,应用程序可以使用此类更新Windows显示,通常在MFC应用程序的OnPaint()函数中使用CMetaFileDC这个设备环境代表Windows元文件,包含一系列命令以重新产生图像。要创建独立于设备的文件时可使用这种DC,用户可以回放这种文件来创建图像①CWindowDC类与CPaintDC和CClientDC类的区别■绘图区域不同:CWindowDC类与CPaintDC和CClientDC类的区别的一个方面就是绘图区域不同。用CPaintDC类和CClientDC类的对象绘制图形时,绘制区只能是客户区,而不能在非客户区,而CWindowDC可以在非客户区进行图形绘制。■绘图坐标系不同:在CWindowDC绘图类下,坐标系是建立在整个屏幕上的,在像素坐标方式下,坐标原点在屏幕的左上角,而在CPaintDC和CClientDC绘图类下,坐标系是建立在客户区上的,在像素坐标方式下,坐标原点在客户区的左上角。②CPaintDC类与CClientDC类的区别■绘图机制不同:CPaintDC类与CClientDC类都是在窗口的客户区内绘制图形,但两者在绘制机制上有着本质的区别。CPaintDC类应用在OnPaint函数中,以响应Windows的WM_PAINT消息,而CClientDC应用在非响应WM_PAINT消息的情况下。CPaintDC类响应WM_PAINT消息,自动完成绘制,这对维护图形的完整性有着重要的作用。例如在一个窗口中,已经绘制了n条直线,这个窗口的完整性可能会被破坏(如被对话框覆盖),当破坏完整性的程序结束时,即覆盖取消,这个窗口就会接收到一个WM_PAINT消息,得到此消息后,激活消息处理函数(如OnPaint)进行窗口绘制。CPaintDC类对象就担负着此时的绘制工作。如果现在想在屏幕上再绘制一条直线(如用鼠标实时绘制,当第二次单击鼠标左键时完成绘制),就要用到CClinetDC类,这个类可以实时的将图形绘制在屏幕上。如果用CPaintDC完成同样的工作,只能发出指令让包含要绘制这条直线的屏幕部分重画,把这条直线绘制到屏幕上。当然,这个重画区域内的其他图形元素同时也会重画。■适用范围不同:CPaintDC类只能支持屏幕显示,而CClientDC类除了支持屏幕显示以外,还支持打印。`CDC类中的函数除了绘制图形的函数以外,还有以Get开头的获取绘图属性的函数,以Set开头的设置绘图属性的函数。3.常用绘图函数示例CDC类中封装了一大批用来绘图的函数,除了文本输出函数TextOut以外,介绍几个常用的绘图函数,函数的原型以及更多的绘图函数用法查阅MSDN。①画点//绘制一个彩色点pDC-TextOut(20,20,点);pDC-SetPixel(100,40,RGB(255,0,0));上面的代码表示用红色画一个点。RGB是一个宏,可以将颜色的三个R(Red)、G(Green)、B(Blue)分量值转换为Windows的颜色数据类型COLORREF(格式为0x00bbggrr),三个分量分别表示红、绿、蓝颜色的多少,取值范围为0~255。常用的8种颜色如下表所示:3常用的8种纯色RGB颜色RGB值颜色RGB(0,0,0)黑色RGB(255,255,255)白色RGB(255,0,0)红色RGB(0,255,0)绿色RGB(0,0,255)蓝色RGB(255,255,0)黄色RGB(0,255,255)青色RGB(255,0,255)品红②画线段//绘制线段pDC-TextOut(320,20,线段);pDC-MoveTo(400,40);pDC-LineTo(500,40);上面的代码画线,MoveTo函数移动画笔到一点,LineTo函数画线。③画折线(多义线)//绘制折线pDC-TextOut(20,170,折线);POINTpolyline[4]={{240,240},{80,120},{240,120},{80,240}};pDC-Polyline(polyline,4);上面的代码将给定的4个点顺序连成折线,函数中第一个参数为折线顶点数组名,第二个参数表示一共有几个点构成折线(最小必须为2)。POINT是Windows的一种结构,用来标识一个点,它有两个成员变量,分别用来表示点的X和Y坐标;在MFC类库中,CPoint封装了这种结构。④画矩形//绘制矩形pDC-TextOut(320,170,矩形);pDC-Rectangle(390,110,600,230);此函数只能画平行于屏幕的矩形,前两个参数分别为矩形的左上角点的X和Y坐标,第三、四个参数分别为矩形的右下角点的X和Y坐标。⑤画椭圆//绘制椭圆pDC-TextOut(20,320,椭圆);pDC-Ellipse(80,260,280,380);此函数画一个由4个参数表示的矩形的内切椭圆。CDC里没专门画圆的函数,画圆仍然使用Ellipse函数。使X和Y方向的长度相等,这时画出来的就是一个圆。⑥画多边形//绘制多边形pDC-TextOut(320,320,多边形);POINTpolygon[3]={{380,330},{530,260},{500,360}};pDC-Polygon(polygon,3);上面的代码将给定三个点顺序首尾连成封闭的多边形,函数中第一个参数为多边形顶点数组名,第二个参数表示多边形顶点的数目。新建一个Graph单文档工程,并在CGraphView类的OnDraw函数中加入上述代码:编译并运行程序,可见输出的图形。4.获取设备环境4在窗口中绘图,必须首先取得窗口的设备环境,如果不在CDC类中进行绘制,就必须首先想办法获取对应的设备环境(或者一个指向设备环境的指针)。①使用GetDC函数GetDC函数用于获取指定窗口工作区的显示器设备环境,其原型声明如下:CDC*CWnd::GetDC();函数不带任何参数,如果函数调用成功,则返回标识CWnd客户区的设备环境,否则返回NULL。返回指针可能是临时性的,所以应该把它保存下来供以后使用。对于公用的设备环境,GetDC成员函数为每一次被获取的设备环境指定默认属性。对于私有的设备环境GetDC成员函数保持它先前所具有的属性不变。设备环境可以用于图形设备接口(GDI)函数在客户区中绘图。一般完成作图之后,用GetDC成员函数获取的设备环境必须通过调用ReleaseDC成员函数来释放。因为在一个给定的时刻,系统只有五个公共的设备环境是可用的,如果使用了设备环境后不释放,有可能会妨碍其他的应用程序访问设备环境。ReleaseDC用于释放一个设备环境,以便该设备环境可以被其他应用程序申请使用。其原型声明如下:intReleaseDC(CDC*pDC);其中pDC为待释放的设备环境的指针。如果释放成功,函数返回非零值,否则,函数返回零。下面的代码表示在单击某个菜单时画一个椭圆:voidCGraphView::OnDrawEllipse(){CDC*pDC;//调用CGraphView::GetDC()获取设备环境pDC=GetDC();pDC-Ellipse(0,0,100,100);//使用完后调用CGraphView::ReleaseDC()释放设备环境ReleaseDC(pDC);}②直接构造CDC对象声明一个CDC类或者其派生类对象,获取设备环境,方法如下:CClientDCdc(CWnd*);构造一个对象,间接使用了GetDC成员函数。当用一个C++的类声明一个对象时,系统会自动调用该类的构造函数,而在CClientDC类的构造函数中就调用GetDC函数。当对象被释放时,又会自动调用该类的析构函数,而在其析构函数中,则调用了ReleaseDC函数来释放设备环境。因此,前面的代码可以改为:voidCGraphView::OnDrawEllipse(){CClientDCdc(this);dc.Ellipse(0,0,100,100);}这样不用用户自己去释放设备环境,在CClinetDC对象被折构时会自动释放。二、GDI对象Windows的GDI对象类型是通过MFC库中的类来表示的,其中CGdiObject类是所有5GDI对象的抽象基类,其派生类包括CBitmap类、CBrush类、CFont类、CPen类、CRgn类和CPalette类,继承关系如下图所示。这些派生类对于绘制图形和图像都是非常重要的,经常要使用这些类来创建绘图工具,而很少直接使用基类CGdiObject。设备环境和图形设备接口是实现计算机绘图的两个重要的组成部分,设备环境主要定义了绘图的状态和方式,而图形设备接口则主要定义了用来绘图的工具。设备环境中包含有默认的GDI对象。■CBitmap:位图是一种位矩阵,每一个显示像素都对应于其中的一个或多个位。用户可以利用位图来表示图像,也可以利用它来创建画刷。■CBrush:画刷定义了一种位图形式的像素,利用它可对区域内部填充颜色。■CFont:字体是一种具有某种风格和尺寸的所有字符的完整集合,它常常被当作资源存于磁盘中,其中有一些还依赖于某种设备。■CPen:画笔是一种用来画线及绘制有形边框的工具,用户可以指定它的