图形设备接口GDI是Windows的子系统它负责在视频显示器和打印机上显示图形。不但编写Windows应用程序只使用GDI,就是Windows本身也只使用GDI来显示用户界面。 GDI原理 98和NT中图形主要由GDI32.DLL动态链接库输出函数来处理。这些动态链接库调用显示或打印驱动中的例程。GDI通过将程序和不同输出设备格开的方式来实现设备无关的图形。也可以认为GDI是图形设备是图形设备的高级接口。 默认时Windows使用基于象素坐标,而大多数传统图形语言使用“虚拟”坐标系。Windows GDI允许使用两者之一(甚至与物理坐标系)。 GDI函数调用 组成GDI的几百个函数可以分为以下几类: 获取和释放设备描述表函数。 获取设备描述表信息函数。 绘图函数。 设置和获取设备描述表参数函数。 使用GDI对象函数 在屏幕或打印机上显示的图形本身被分为几类: 直线和曲线、填充区域、位图、文本。 其他方面: 映射模式和变换、元文件、区域、路径、裁减、调色板、打印。 获取设备描述表 获取设备描述句柄:BeginPaint和EndPaint。GetDC、GetWindowDC和ReleaseDC。GreateDC和DeleteDC。 获取信息描述表:GreateIC和DeleteDC。 获取内存设备描述表句柄:CreateCompatibleDC和DeleteDC。 获取源文件设备描述表:CreateMetaFile和CloseMetaFile。 获取设备描述表信息 一个设备描述表通常是指一个物理显示设备,通常需要获取有关该设备的信息。可以通过GetDeviceCaps来获得。 保存设备描述表 通常调用GetDC或BeginPaint时,Windows用默认值创建一个新的设备描述表,不会保存上次调用时改变的信息。 如果使用在窗口创建时包含CS_OWNDC标志,基于这个窗口创建的每个窗口都会拥有自己的设备描述表,它一直存在直到窗口被删除。CS_OWNDC只影响GetDC和BeginPaint获得的设备描述表,不影响其他函数获得的设备描述表。 在某些情况下,可能想改变某些设备描述表属性,用改变后的属性进行绘图,然后恢复原来的设备描述表。要简化这一过程,可以通过SaveDC来保存设备描述表状态。然后通过RestoreDC来恢复设备描述表信息。可以在调用RestoreDC前调用SaveDC数次。也可以像汇编中PUSH和POP指令,当调用SaveDC时,不需要保存返回值:SaveDC(hdc),RestoreDC(hdc,-1); 写像素 SetPixel和GetPixel函数来设定和得到像素。 直线 Windows可以画直线、椭圆和贝塞尔样条。 LineTo画直线 Polyline和PolylineTo画一系列相连的直线。 PolyPolyline画多组相连的线。 Arc画椭圆线 PolyBezier和PolyBezierTo画贝塞尔样条 另外NT以上系统还支持: ArcTo和AngleArc画椭圆线。 PolyDraw画一系列相连的线以及贝塞尔样条。 即画线也填充所画图形的封闭区域的函数: Rectangle画矩形 Ellipse画椭圆 RoundRect画圆角矩形 Pie画椭圆的一部分,像扇形。 Chord画椭圆的一部分,呈弓形。 画一条直线必须用到两个函数,第一个指明线的起点,第二个指定线的终点:MoveTeEx和LineTo。 如果想获得当前位置,可以调用GetCurrentPositionEx, 边界框函数 边框函数严格来说不是画线函数,这些函数是在画线,但他们同时又使用当前区域填充刷子填充一个封闭区域。 使用现有画笔 Windows使用设备描述表中当前选中的“画笔”来画线。画笔决定线的颜色、宽度和线形。Windows提供三种画笔BLACK_PEN, WHITE_PEN, NULL_PEN。也可以自己定制画笔。 Windows使用句柄来的引用画笔。类型为HPEN。 调用GetStockObject可以获得现有画笔句柄。将现有句柄选入设备描述表SelectObject。 画笔的创建、选择和删除 CreatePen或CreatePenIndirect创建一个“逻辑画笔”。然后调用SelectObject将画笔选进设备描述表。在任何时候只能有一种画笔选进设备描述表。画笔是一种GDI对象,是可以创建的六种GDI之一。其他五种是刷子、位图、区域、字体和调色板。 在创建这些GDI对象时,要遵守一下三条规则: 1 最后要删除自己创建的GDI对象。 2 当GDI对象正在有效设备描述表中,不要删除它。 3 不要删除现有对象。 可以通过CreatePenIndirect创建逻辑画笔,LOGPEN逻辑画笔结构。创建画笔不需要使用设备描述表句柄作为参数,他们直到调用SelectObject后才与设备描述表发生联系。 填充空隙 使用点画笔和虚线画笔会产生有趣的问题:点和虚线之间的空隙会怎样。 空隙的着色取决于设备描述表的两个属性:背景模式和背景颜色。可以通过SetBkColor来填充背景颜色,通过SetBkMode来设置背景模式。 绘图方式 设备描述表中的绘图方式也影响显示器上所画线的外观。也就是当Windows使用画笔画线时,它执行画笔像素与目标位置处原来像素之中某种按位布尔运算。称为“光栅运算”。 可以通过调用SetROP2来设置新的绘图模式,可以用GetROP2来获取当前绘图方式。 绘制填充区域 Windows用设备描述表中选择的当前画笔来画图形的边界框,边界框还使用当前的背景方式、背景颜色和绘图方式。图形以当前设备描述表中选择的刷子来填充。 图形以当前设备描述表中选择的刷子来填充。就和您选择画笔一样,Windows将HBRUSH定义为刷子句柄。 通过GetStockObject来获取刷子,然后通过SelectObject将它选进设备描述表。 用画刷填充内部 画刷是一个8x8的位图,它水平和垂直的重复使用来填充内部区域。Windows还有5个函数,让您可以创建画刷: CreateSolidBrush(crColor); CreateHatchBrush(iHatchStyle, crColor); 可以使用CreatePatternBrush和CreateDIBPatternBrushPt创建基于位图的画刷。 最后一个是创建逻辑画刷CreateBrushIndirect(&logbrush);其中参数类型为LOGBRUSH的结构。 GDI映射方式 默认时程序都是默认客户区左上角,以像素为单位绘制。“映射方式”是可以改变的。Windows定义了8种映射方式。可以通过SetMapMode改变窗口的映射方式。相对的GetMapMode可以获得当前映射方式。 设备坐标和逻辑坐标 改变映射方式是不会影响到非GDI函数,甚至一些GDI函数永远使用设备坐标。GetSystemMetrics不是GDI函数所以它总是以设备单位为肚量返回大小。GetDeviceCaps虽然是GDI函数,但Windows仍对HORZRES和VERTRES以设备单位作为返回值。但是GetTextMetrics调用种返回的TEXTMETRIC结构是逻辑单位。 设备坐标系 尽管Windows大多数时间在窗口的客户区工作,但Windows在不同的时间使用不同另外两种设备坐标: “屏幕坐标”:屏幕左上为(0 , 0)屏幕坐标在WM_MOVE消息以及CreateWindow和MoveWindow(非子窗口)、GetMessagePos、GetCursorPos、SetCursorPos、GetWinowRect,以及WindowFromPoint “整窗口坐标”:以程序整个窗口为基准。基本很少使用,GetWindowDC时使用。 “屏幕坐标”:程序客户区左上角为基准,GetDC和BeginPaint时。 视口和窗口 映射方式定义了Windows如何将GDI函数中指定的逻辑坐标映射为设备坐标。映射方式用于定义从“窗口”(逻辑坐标)到“视口”(设备坐标)的映射。 通常“视口”与客户区相同。“窗口”是基于逻辑坐标的。 Windows提供了两个函数将视口(设备)坐标和窗口(逻辑)坐标进行转换。DPtoLP和LPtoDP。 处理MM_TEXT Windows提供了SetViewportOrgEx和SetWindowOrgEx,用来改变视口和窗口的原点。通常着两个函数不会同时使用。对应GetViewportOrgEx和GetWindowOrgEx得到原点。 也可以通过改变原点来实现调整输出的坐标。 “度量”映射方式 Windows包含5种屋里尺寸来表示逻辑坐标的映射方式。由于x轴和y轴逻辑坐标映射为相同物理单位,这些映射方式能画出不变形的圆和矩形。 这5种映射方式使y轴变为向上递增。 “自定义”映射方式: MM_ISOTROPIC和MM_ANISOTROPIC这两种方式可以改变Windows用来转换逻辑和设备坐标的转换因子。 如果想要使用任意的轴时都保证两个轴上的逻辑单位相同,则应该使用MM_ISOTROPIC方式。 然后使用SetWindowExtEx和SetViewportExtEx来改变范围。一般来说可以用SetWindowExtEx来设置希望的逻辑窗口尺寸。用客户区实际宽和高作为SetViewportExtEx的参数。Windows调整这些范围时,必须让逻辑窗口适应物理窗口,这就很可能导致客户区的一段落到了逻辑窗口的外边。 MM_ANISOTROPIC映射方式下设置窗口和视口的范围时,Windows会调整范围,以便两条轴上的逻辑单位具有相同的物理尺度。 矩形区域和裁减 三个绘图函数: FillRect使用指定画刷填充举行。 FrameRect使用画刷画矩形框。 InvertRect将矩形中像素反转。 Windows还提供了9个函数,虽然可以通过其他的方式也能实现。但通过它们更容易清楚的操作RECT结构。 SetRect设置一个矩形。 OffsetRect移动矩形。 InflateRect增减矩形尺寸。 SetRectEmpty清空rect CopyRect复制矩形。 IntersectRect获取两个矩形交集。 UnionRect获取两个矩形的并集。 IsRectEmpty确定矩形是否为空。 PtInRect确定点是否在矩形内。 创建和绘制区域 区域是对显示器上一部分的描述,这个范围是矩形、多边形和椭圆的组合。区域用于绘制和剪裁通过将区域选进设备描述表,就可以用区域来进行裁减。通过将区域选进设备描述表,可以将可以绘制的范围限制为选进的区域。 当创建区域时,Windows返回一个区域的句柄HRGN。 CreateRectRgn和CreateRectRgnIndirect创建矩形区域。 CreateEllipticRgn和CreateEllipticRgnIndirect创建椭圆区域。 CreateRoundRectRgn创建圆角矩形区域。 CreatePolygonRgn创建多边形区域。 区域最重要的功能是将多个区域组合: CombineRgn合并区域。 区域的句柄可以用于4个绘图函数: FillRgn,FrameRgn,InvertRgn和PaintRgn前三个函数和矩形的函数相同。PaintRgn用设备描述表中当前的画刷填充指定区域。 当用完一个区域后,可以像其他GDI对象一样删除它。 矩形与区域的剪裁 区域也在剪裁中扮演了重要角色。Windows有两个用于区域而不是矩形的函数,他们类似于InvalidateRect。 InvalidateRgn和ValidateRgn当收到一个由无效区域引起的WM_PAINT消息时,裁减区域不一定是矩形。可以使用:SelectObject和SelectClipRgn通过将一个区域选进设备描述表来创建自己的裁减区域。 GDI为剪裁区域建立一份副本,所以在将它选进设备描述表后,用户可以删除它。 Windows还提供了几个对裁减区域进行操作的函数: ExcludeClipRect可以用于将一个矩形从裁减区域里排除。 IntersectClipRect用于创建一个新的裁减区域,它是前一个剪裁区域与矩形的交集。 OffsetClipRgn用于将剪裁区域移动到客户区另一部分。 PeckMessage和GetMessage PeekMessage最后一个参数设置为PM_REMOVE时,则PeekMessage将消息删除,如果设置为PM_NOREMOVE,将不删除消息。它使程序可以检测程序队列中的下一个消息。 GetMessage不将控制权返回给程序,直到从程序的消息队列中获取消息。但PeekMessage总是立刻返回。不论消息是否出现。当消息队列中有一个消息时,PeekMessage返回非零,并且将按通常方式处理消息。当队列中没有消息PeekMessage返回0(FALSE)。