Windows程序GDI绘.ppt_第1页
Windows程序GDI绘.ppt_第2页
Windows程序GDI绘.ppt_第3页
Windows程序GDI绘.ppt_第4页
Windows程序GDI绘.ppt_第5页
已阅读5页,还剩87页未读 继续免费阅读

下载本文档

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

文档简介

,用C+语言实现Windows图形输出,1、设备场境概念,2、使用GDI绘图对象,3、使用GDI坐标系统,C+程序设计,4、使用GDI绘图,2,13.2.7图形输出,Windows应用程序不支持标准输出函数(如printf),应用程序输出包括文字在内的所有数据均是以图形方式“绘制”到窗口上的。Windows通过图形设备接口GDI对图形输出进行支持。GDI为应用程序提供了与显示器、打印机等输出设备无关的图形输出接口,使得程序员从各种显示、打印设备的直接处理中解脱出来。,3,13.2.7图形输出,GDI由几百个函数和与此相关的数据类型、宏定义和结构体组成。主要有:获取和释放(或创建和删除)设备描述表函数、获取设备信息函数、使用GDI绘图对象函数、绘图函数、设置和获取设备参数函数等,其显示的图形类型(简称图元)有:直线、曲线、填充、位图、文本等。,4,13.2.7图形输出,1设备场境Windows对图形显示设备进行了封装,形成了一个统一的虚拟图形显示设备。应用程序可以在这个虚拟设备上进行绘图,而虚拟设备图形转换为物理设备图形的任务则由设备驱动程序去完成。这个虚拟图形设备用一个包含各种设备属性的数据结构来表示,称为设备场境DC(devicecontent),又称设备上下文。如图所示,设备场境DC是指可以用来输出图形的对象,例如显示器、打印机、某个窗口等等,设备场境句柄HDC是指向某个设备场境的类似指针的数据类型。,5,13.2.7图形输出,也就是说,从应用程序的角度来看,设备场境DC就是Windows提供的一个“画板”,程序在其上绘图。当程序员想在一个图形输出设备(例如显示器或者打印机)上绘图时,必须首先获得设备场境句柄,然后以此为参数调用GDI函数绘图。,6,13.2.7图形输出,图13.14设备场景DC示意,7,13.2.7图形输出,Windows提供了几种获取设备场境句柄的方法。如果在处理一条消息时获取了设备场境句柄,那么应该在退出窗口过程WndProc之前释放它或者删除它。一旦释放了DC句柄,它就不能再使用了。,8,13.2.7图形输出,最常用的获取设备场境句柄的方法是在处理WM_PAINT消息时,使用BeginPaint和EndPaint调用:其中ps、hdc定义如下:,hdc=BeginPaint(hWnd,/客户区绘图结束,PAINTSTRUCTps;HDChdc;,9,13.2.7图形输出,变量hdc是设备场境句柄类型HDC变量,变量ps是类型PAINTSTRUCT的结构体变量,该结构包含一个名为rcPaint的RECT矩形结构成员,rcPaint定义一个包围窗口客户区无效范围的矩形。使用从BeginPaint获得的DC句柄,只能在这个区域内绘图。只要使用了BeginPaint就必须要用且只能用EndPaint释放DC句柄。,10,13.2.7图形输出,WM_PAINT消息是当窗口客户区域的一部分或全部变为“无效”,以至于必须“刷新”时发生。例如新建窗口、窗口大小的调整、窗口移动、被覆盖部分的恢复都会产生刷新请求。如图所示,窗口A被另一个窗口B覆盖的区域称为“无效”区域,因为当窗口B从覆盖区域移走后,图中阴影部分对于窗口A来说必须要刷新,否则它是窗口B的图形。,11,13.2.7图形输出,图13.15需要重画的无效区域,12,13.2.7图形输出,应用程序还可以在处理非WM_PAINT消息时获取设备场境句柄,例如:,hdc=GetDC(hWnd);/hdc得到客户区DC句柄/GDI绘图调用.ReleaseDC(hWnd,hdc);/释放客户区DC句柄,13,13.2.7图形输出,GetDC得到的设备场境句柄是窗口hWnd客户区的句柄。这组调用与BeginPaint和EndPaint的区别是利用从GetDC返回的句柄可以在整个客户区上绘图,然而GetDC不会使客户区中任何区域可能的无效区域变成有效,从显示效果上来看,GetDC的绘图结果将会在下次WM_PAINT消息刷新后“消失”了。,14,13.2.7图形输出,应用程序还可以获取整个窗口的设备场境句柄,例如:GetWindowDC得到的设备场境句柄,除客户区之外,还包括窗口的标题栏、菜单、滚动条和外框。使用GetDC和GetWindowDC得到的设备场境句柄,只能调用ReleaseDC释放。,hdc=GetWindowDC(hWnd);/hdc得到窗口DC句柄/GDI绘图调用.ReleaseDC(hWnd,hdc);/释放窗口DC句柄,15,13.2.7图形输出,BeginPaint、GetDC和GetWindowDC获得的设备场境句柄与显示器的窗口是相关的,获取设备场境句柄的另一个更通用的函数是CreateDC,例如:其中lpszDriver参数指定设备驱动名称,lpszDevice指定设备名称,lpszOutput和lpInitData一般设为NULL。,hdc=CreateDC(lpszDriver,lpszDevice,lpszOutput,lpInitData);/hdc得到设备DC句柄/GDI绘图调用.DeleteDC(hdc);/删除设备DC句柄,16,13.2.7图形输出,例如:得到整个屏幕的设备场境句柄,而:得到打印机的设备场境句柄,其中lpszDevice是打印机设备的名称。,hdc=CreateDC(DISPLAY,NULL,NULL,NULL);,hdc=CreateDC(NULL,lpszDevice,NULL,NULL);,17,13.2.7图形输出,当使用位图时,需要创建一个内存设备场境,例如:创建了一个基于hdc设备特性的内存设备场境句柄hdcMem。在hdcMem句柄上绘制的图形不会显示出来,它只是在内存中“绘图”,因此一般需要调用GDI位图函数将它复制到可显示DC句柄上才能看到绘图结果。使用CreateDC和CreateCompatibleDC得到的设备场境句柄,只能调用DeleteDC删除。,hdcMem=CreateCompatibleDC(hdc);/hdcMem得到内存DC/GDI绘图调用.DeleteDC(hdcMem);/删除内存DC句柄,18,13.2.7图形输出,2GDI绘图对象GDI绘图对象是绘制图形的工具,表13-14列出了常用的Windows绘图工具。,19,13.2.7图形输出,表13-14Windows绘图工具,20,13.2.7图形输出,GDI绘图对象的使用必须按如下步骤进行:创建绘图对象或调用GetStockObject获取预定义绘图对象。调用SelectObject将绘图对象选进设备场境DC中。调用DeleteObject删除绘图对象(GetStockObject获取的对象除外)。,21,13.2.7图形输出,创建和删除绘图对象一般有两个时机。一个时机是在WM_CREATE消息处理中创建绘图对象,在WM_DESTROY消息处理中删除绘图对象,即在窗口建立时创建对象,窗口销毁时删除对象。这样得到的绘图对象在整个窗口运行期间一直有效,优点是不用频繁地创建和删除对象,缺点是绘图对象始终占用内存,存储开销大。另一个时机是在设备场境句柄有效期间,例如在BeginPaint、GetDC、GetWindowDC、CreateDC、CreateCompatibleDC之后创建绘图对象,在EndPaint、ReleaseDC、DeleteDC之后删除绘图对象。Windows规定不能删除设备场境当前选择的绘图对象。,22,13.2.7图形输出,下表列出了各种GDI绘图对象的创建函数。,23,13.2.7图形输出,表13-15GDI绘图对象创建函数,24,13.2.7图形输出,续表13-15GDI绘图对象创建函数,25,13.2.7图形输出,续表13-15GDI绘图对象创建函数,26,13.2.7图形输出,Windows系统在应用程序初始化时提供了一套默认的绘图工具,例如默认的画笔工具颜色是黑色,所以这时绘制出来的线条都是黑色的。如果应用程序认为默认绘图工具不合适,则需要另行创建绘图对象,并将其选进设备场境中,函数原型为:参数hdc是欲使用绘图对象的DC句柄,hgdiobj是绘图对象句柄,即绘图对象创建函数的返回值。SelectObject的返回值是前一个绘图对象句柄,绘制图形时安全的做法是将默认绘图对象句柄保存下来,在释放或删除DC句柄前将默认绘图对象选进DC句柄。,HGDIOBJSelectObject(HDChdc,HGDIOBJhgdiobj);,27,13.2.7图形输出,3GDI坐标系统大多数GDI绘图函数需要坐标值或尺寸,使用逻辑单位,实际图形输出时,Windows将逻辑单位转换为设备单位,即像素。这种转换是由映射方式、窗口和视口的原点及其范围控制的。(1)映射方式Windows定义了8种映射方式,它们的标识符和含义见表所示。,28,13.2.7图形输出,表13-16映射方式,29,13.2.7图形输出,可以调用SetMapMode为DC设置映射方式,函数原型为:参数fnMapMode是8种映射方式之一。可以获取当前DC的映射方式,函数原型为:,intSetMapMode(HDChdc,intfnMapMode);,intGetMapMode(HDChdc);,30,13.2.7图形输出,设备场境默认的映射方式为MM_TEXT。在这种映射方式下,逻辑单位与物理单位相同,都是以像素为单位。例如:会在距离客户区左端8像素、上端16像素的位置开始输出“Hello”。,TextOut(hdc,8,16,Hello,5);,31,13.2.7图形输出,如果映射方式设置为MM_LOMETRIC,例如:则逻辑单位是十分之一毫米,那么会在距离客户区左端5毫米、上端1毫米的位置开始输出字符串,这样的映射方式更适合打印机。,SetMapMode(hdc,MM_LOMETRIC);,TextOut(hdc,50,-10,Hello,5);,32,13.2.7图形输出,(2)设备坐标系Windows对所有非GDI函数,甚至一部分GDI函数使用设备坐标,以像素为单位。从显示设备来看,存在三种不同的设备坐标系。如图所示是三种设备坐标系。,33,13.2.7图形输出,图13.163种设备坐标系,34,13.2.7图形输出,整个屏幕是一个“屏幕坐标”,屏幕的左上角为(0,0)点;如果使用CreateDC创建屏幕设备场境句柄时,默认情况下逻辑坐标将被映射为屏幕坐标。整个窗口是一个“窗口坐标”,包括标题栏、窗口外框、菜单、滚动条等,(0,0)点是窗口的左上角;如果用GetWindowDC获取窗口设备场境句柄,则逻辑坐标会转换成客户区坐标。最常使用的设备坐标是“客户区坐标”,(0,0)点是客户区的左上角,当使用GetDC或BeginPaint获得设备场境句柄时,逻辑坐标默认会转换为客户区坐标。,35,13.2.7图形输出,用函数ClientToScreen和ScreenToClient可以将客户区坐标转换成屏幕坐标,或者反过来将屏幕坐标转换成客户区坐标,可以使用GetWindowRect函数获取屏幕坐标下的窗口位置和大小。,36,13.2.7图形输出,(3)视口和窗口视口(viewport)是计算机屏幕上一块显示区域,随着在GDI中所使用的设备场境句柄的不同,该区域可以是客户区、整个窗口或整个屏幕。视口是基于设备坐标(像素)的。通常视口和客户区相同,(0,0)点在客户区左上角,x的值向右增加,y的值向下增加。,37,13.2.7图形输出,与视口中显示的图形相对应的原始图形区域称为窗口。注意,在这里使用的术语“窗口”不是指屏幕上显示的窗口对象,而是从现实世界角度所看到的图形。窗口是基于逻辑坐标的,逻辑坐标可以是像素、毫米、英寸或者任何其他单位。如图说明了窗口和视口的关系。,38,13.2.7图形输出,图13.17视口与窗口关系,39,13.2.7图形输出,对于所有的映射方式,利用下面两个公式可以将窗口坐标转换为视口坐标:其中是待转换的逻辑点,是转换后的设备坐标点,是逻辑坐标的窗口原点,是设备坐标的视口原点,是逻辑坐标的窗口范围,是设备坐标的视口范围。此公式意味着逻辑窗口原点总被映射为设备视口原点。,40,13.2.7图形输出,Windows提供了两个函数将设备点与逻辑点相互转换,函数原型为:,BOOLDPtoLP(HDChdc,LPPOINTlpPoints,intnCount);BOOLLPtoDP(HDChdc,LPPOINTlpPoints,intnCount);,41,13.2.7图形输出,DPtoLP函数将设备点转换为逻辑点,LPtoDP函数将逻辑点转换为设备点,lpPoints是指向POINT结构数组的指针,nCount表示存储在lpPoints中要转换的点的个数。例如可将GetClientRect获取的客户区大小(设备单位)转换为逻辑坐标,代码如下:,RECT,42,13.2.7图形输出,(4)处理MM_TEXT对于MM_TEXT映射方式,默认的原点和范围如下:窗口原点:(0,0)可以改变视口原点:(0,0)可以改变窗口范围:(1,1)不可改变视口范围:(1,1)不可改变,43,13.2.7图形输出,视口范围与窗口范围的比例为1,所以不用在逻辑坐标与设备坐标之间进行缩放,上述两式可以简化为:这种映射方式称为“文本”映射方式,即与人们阅读文本从左至右、从上至下的习惯相同,如图(a)所示。,44,13.2.7图形输出,图13.18视口与窗口坐标转换,45,13.2.7图形输出,Windows提供函数可用来改变视口和窗口的原点,原型如下:SetWindowOrgEx改变窗口原点,SetViewportOrgEx改变视口原点,(x,y)为新的原点值,lpPoint用来接收先前的原点值,设为NULL表示不用接收。一般情况下,很少同时使用这两个函数,因为窗口和视口原点同时改变会使坐标变换的计算复杂化。,BOOLSetWindowOrgEx(HDChdc,intX,intY,LPPOINTlpPoint);BOOLSetViewportOrgEx(HDChdc,intX,intY,LPPOINTlpPoint);,46,13.2.7图形输出,例如,假定客户区宽为cxClient、高为cyClient,如果想将逻辑原点定义为客户区的中心,可进行如下调用:SetViewportOrgEx的参数总是使用设备单位。现在逻辑原点从(0,0)将映射为设备点(cxClient/2,cyClient/2),客户区坐标系变成如图(b)所示。,SetViewportOrgEx(hdc,cxClient/2,cyClient/2,NULL);,47,13.2.7图形输出,逻辑x轴的范围从-cxClient/2到+cxClient/2,逻辑y轴的范围从-cyClient/2到cyClient/2。例如想从客户区的左上角开始显示字符串,则需要负坐标:用下面的SetWindowOrgEx调用可以获得与上面相同的效果:,TextOut(hdc,-cxClient/2,-cyClient/2,Hello,5);,SetWindowOrgEx(hdc,-cxClient/2,-cyClient/2,NULL);,48,13.2.7图形输出,SetWindowOrgEx的参数总是使用逻辑单位。在这个调用之后,逻辑点(-cxClient/2,-cyClient/2)映射为设备点(0,0),即客户区的左上角。而下面同时调用:的结果是逻辑点(-cxClient/2,-cyClient/2)将映射为设备点(cxClient/2,cyClient/2),客户区坐标系变成如图(c)所示。,SetViewportOrgEx(hdc,cxClient/2,cyClient/2,NULL);SetWindowOrgEx(hdc,-cxClient/2,-cyClient/2,NULL);,49,13.2.7图形输出,(1)绘图方式在Windows中,绘图的最终结果可以通过设定不同的绘图方式来控制,其函数原型为:参数fnDrawMode为绘图模式,返回值为先前的绘图模式。常用的绘图模式见表13-17。当Windows使用画笔画线时,它实际上执行画笔像素颜色值与目标位置处原来像素颜色值的位运算,称为“光栅运算”。,intSetROP2(HDChdc,intfnDrawMode);,50,13.2.7图形输出,表13-17绘图方式,51,13.2.7图形输出,续表13-17绘图方式,52,13.2.7图形输出,续表13-17绘图方式,53,13.2.7图形输出,(2)画点和线如下是GDI画点和线的绘图函数。,/画点COLORREFSetPixel(HDChdc,intX,intY,COLORREFcrColor);/移动画笔到指定位置BOOLMoveToEx(HDChdc,intX,intY,LPPOINTlpPoint);/画直线BOOLLineTo(HDChdc,intnXEnd,intnYEnd);/画由一系列点相连的直线BOOLPolyline(HDChdc,CONSTPOINT*lppt,intcPoints);BOOLPolylineTo(HDChdc,CONSTPOINT*lppt,DWORDcCount);,54,13.2.7图形输出,(2)画点和线如下是GDI画点和线的绘图函数。,/画多组相连的直线BOOLPolyPolyline(HDChdc,CONSTPOINT*lppt,CONSTDWORD*lpdwPolyPoints,DWORDcCount);/画圆弧BOOLArc(HDChdc,intnLeftRect,intnTopRect,intnRightRect,intnBottomRect,intnXStartArc,intnYStartArc,intnXEndArc,intnYEndArc);/画贝塞尔样条曲线BOOLPolyBezier(HDChdc,CONSTPOINT*lppt,DWORDcPoints);BOOLPolyBezierTo(HDChdc,CONSTPOINT*lppt,DWORDcCount);,55,13.2.7图形输出,例如:在点(20,20)处画一个红点,COLORREF类型用于指定颜色值。颜色值是由红、绿、蓝三个颜色分量组成,每种颜色分量的值为0255,0表示无此颜色,255表示此颜色最大值。一般使用RGB宏定义产生颜色值,定义如下:,SetPixel(hdc,20,20,RGB(255,0,0);,#defineRGB(r,g,b)(COLORREF)(BYTE)(r)|(WORD)(BYTE)(g)8)|(DWORD)(BYTE)(b)16),56,13.2.7图形输出,例如:从(100,100)到(200,200)画一条直线。MoveToEx用于将画笔移动到画线起点,LineTo从当前的起点画线到终点。,MoveToEx(hdc,100,100,NULL);LineTo(hdc,200,200);,57,13.2.7图形输出,如果希望用别的线条颜色或者线宽画线,那么需要创建不同的画笔对象,例如:,hPen=CreatePen(PS_SOLID,4,RGB(255,0,255);/创建紫色画笔hOldPen=SelectObject(hdc,hPen);/将画笔选进DC中,此后画线均用此画笔,直到另选画笔为止LineTo(hdc,300,100);/画紫色线,58,13.2.7图形输出,(3)画矩形框、圆和多边形如下是GDI画封闭形状的绘图函数,封闭形状用画笔画线,用画刷填充形状。,/画椭圆BOOLEllipse(HDChdc,intnLeftRect,intnTopRect,intnRightRect,intnBottomRect);/画矩形框BOOLRectangle(HDChdc,intnLeftRect,intnTopRect,intnRightRect,intnBottomRect);/画带圆角的矩形框BOOLRoundRect(HDChdc,intnLeftRect,intnTopRect,intnRightRect,intnBottomRect,intnWidth,intnHeight);,59,13.2.7图形输出,/画饼图BOOLPie(HDChdc,intnLeftRect,intnTopRect,intnRightRect,intnBottomRect,intnXRadial1,intnYRadial1,intnXRadial2,intnYRadial2);/画弦BOOLChord(HDChdc,intnLeftRect,intnTopRect,intnRightRect,intnBottomRect,intnXRadial1,intnYRadial1,intnXRadial2,intnYRadial2);/填充矩形intFillRect(HDChDC,CONSTRECT*lprc,HBRUSHhbr);/画矩形边界intFrameRect(HDChDC,CONSTRECT*lprc,HBRUSHhbr);,60,13.2.7图形输出,/画封闭的多边形BOOLPolygon(HDChdc,CONSTPOINT*lpPoints,intnCount);/画多组封闭的多边形BOOLPolyPolygon(HDChdc,CONSTPOINT*lpPoints,CONSTINT*lpPolyCounts,intnCount);,61,13.2.7图形输出,如果希望用别的填充颜色或者填充图案,那么需要创建不同的画刷对象,例如:,hbr=CreateSolidBrush(RGB(255,0,0);/创建红色画刷hOldBrush=SelectObject(hdc,hbr);/将画刷选进DC中,此后填充均用此画刷,直到另选画刷为止Rectangle(hdc,300,100,400,200);/画矩形框且填充红色,62,13.2.7图形输出,(4)画文字如下是GDI文字输出的绘图函数。,/在指定坐标开始输出cbString个字符,如果输出全部字符串,cbString设为-1BOOLTextOut(HDChdc,intnXStart,intnYStart,LPCTSTRlpString,intcbString);/在一个矩形范围内输出字符串,uFormat值表示使用对齐等格式intDrawText(HDChDC,LPCTSTRlpString,intnCount,LPRECTlpRect,UINTuFormat);/设置文本颜色COLORREFSetTextColor(HDChdc,COLORREFcrColor);/设置文本背景颜色COLORREFSetBkColor(HDChdc,COLORREFcrColor);,63,13.2.7图形输出,(4)画文字如下是GDI文字输出的绘图函数。,/设置文本字符间距intSetTextCharacterExtra(HDChdc,intnCharExtra);/设置文本对齐方式UINTSetTextAlign(HDChdc,UINTfMode);/设置背景色模式,iBkMode=OPAQUE使用背景色,iBkMode=TRANSPARENT背景是透明的intSetBkMode(HDChdc,intiBkMode);,64,13.2.7图形输出,例如:,TextOut(hdc,8,16,Hello,5);/输出文字SetTextColor(hdc,RGB(255,255,255);/设置文字颜色SetBkColor(hdc,RGB(0,0,0);/设置文字背景颜色GetClientRect(hWnd,/在客户区中央输出,65,13.2.7图形输出,如果希望在窗口中实现类似printf的格式化输出,可以先调用sprintf将数据“输出”到字符数组中,再调用GDI函数绘制出来。例如:GDI文字输出比标准输出流的输出效果更美观,因为它可以设置文字颜色、背景色、按像素单位设置字符间距、使用字体、设置字号等等。,charbuf100;sprintf(buf,s=%f,3.1415926*13.2*13.2);/输出圆面积s=*r*rTextOut(hdc,300,20,buf,strlen(buf);,66,13.2.7图形输出,(5)画位图和图标GDI可以直接输出位图图像,步骤如下。首先调用LoadBitmap函数加载位图资源,例如:调用GetObject可以得到位图的宽和高,例如:,hBmp=LoadBitmap(hInst,MAKEINTRESOURCE(IDB_PICTURE);/加载位图资源,GetObject(hBmp,sizeof(BITMAP),/bm.bmWidth,bm.bmHeight分别为宽和高,67,13.2.7图形输出,其次,为便于在内存中对位图进行绘图操作,位图对象不是直接选进显示设备DC中,而是创建一个内存DC,将位图对象选进内存DC中。例如:,hdcMem=CreateCompatibleDC(hdc);/创建内存DChOldBmp=(HBITMAP)SelectObject(hdcMem,hBmp);/位图选进内存DC,68,13.2.7图形输出,为了将内存DC的图形结果显示出来,可以调用位图像素复制函数,原型为:例如:,/等比复制hdcSrc的图形到hdcDest中,dwRop表示像素光栅运算模式BOOLBitBlt(HDChdcDest,intnXDest,intnYDest,intnWidth,intnHeight,HDChdcSrc,intnXSrc,intnYSrc,DWORDdwRop);/拉伸复制hdcSrc的图形到hdcDest中,dwRop表示像素光栅运算模式BOOLStretchBlt(HDChdcDest,intnXOriginDest,intnYOriginDest,intnWidthDest,intnHeightDest,HDChdcSrc,intnXOriginSrc,intnYOriginSrc,intnWidthSrc,intnHeightSrc,DWORDdwRop);,/将位图复制到显示设备(420,0)处BitBlt(hdc,420,0,bm.bmWidth,bm.bmHeight,hdcMem,0,0,SRCCOPY);/复制到hdc,69,13.2.7图形输出,可以调用DrawIcon函数输出图标,其函数原型为:例如:,BOOLDrawIcon(HDChDC,intX,intY,HICONhIcon);,hIcon=LoadIcon(hInst,MAKEINTRESOURCE(IDI_APP);/从资源加载图标DrawIcon(hdc,200,200,hIcon);/画图标,70,13.2.7图形输出,(6)双缓冲技术GDI将图形直接绘制在显示设备上时,如果绘制内容较多或者绘制时间较长,会出现显示闪烁。为解决这个问题,可采用双缓冲技术(doublebuffering)。,71,13.2.7图形输出,图13.19双缓冲绘图示意,72,13.2.7图形输出,如图所示,双缓冲原理是在内存中创建一个与屏幕绘图区域一致的内存DC,然后在其上绘制图形,由于闪烁是在内存中,因此不可见。绘制完成后采用BitBlt快速将图形送到显示设备上,从而避免显示闪烁。利用双缓冲技术,可以编写动画和游戏所要求的画面。但GDI绘图过程本身是比较慢的,如果需要编写快速显示的动画或游戏场景时,最好采用专业图形开发库,例如DirectX和OpenGL等。,73,13.2.7图形输出,Windows窗口调整时会产生WM_ERASEBKGND消息,这个消息的作用是通知窗口用背景画刷填充背景,结果也会导致显示闪烁。因此应用程序可以增加OnEraseBkgnd消息处理,用来禁止背景填充,其代码如下:双缓冲技术实现代码如下:,LRESULTOnEraseBkgnd(HWNDhWnd,UINTmessage,WPARAMwParam,LPARAMlParam)/擦除背景消息处理returnFALSE;/不擦除背景,74,13.2.7图形输出,LRESULTOnPaint(HWNDhWnd,UINTmessage,WPARAMwParam,LPARAMlParam)/重绘消息处理PAINTSTRUCTps;HDChdc,hdcMem;HBITMAPhBmp,hOldBmp;HBRUSHhbr;RECTrt;COLORREFcr;intnWidth,nHeight;hdc=BeginPaint(hWnd,75,13.2.7图形输出,hBmp=CreateCompatibleBitmap(hdc,nWidth,nHeight);/创建与显示区域相同的位图对象hOldBmp=(HBITMAP)SelectObject(hdcMem,hBmp);/位图对象选进内存DCcr=GetBkColor(hdc);/获取背景色hbr=CreateSolidBrush(cr);/创建背景色实体画刷FillRect(hdcMem,/处理了这条消息必须返回0,76,13.2.7图形输出,OnBufferPaint函数中的绘图就是在双缓冲DC上进行的。如果将上面代码中的双缓冲开始至结束间的代码替换为:可以看到用与不用双缓冲技术,绘图效果区别是很大的。,OnBufferPaint(hWnd,hdc);,77,13.2.7图形输出,【例13.4】,编写使用GDI绘图的程序。程序基于SDK编程框架(参考例13.3)编写,增加WM_PAINT消息处理。程序需要定义一个位图资源IDB_CAR。,78,13.2.7图形输出,例13.4,1/头文件-2#include/Windows头文件3#includeresource.h/资源头文件4#include5/全局定义-6HINSTANCEhInst;/应用程序实例句柄7HWNDhMainWnd;/主窗口句柄8charszWindowTitle=MainWindow;/主窗口标题9charszWindowClass=SDKWIN32APP;/主窗口类名10structWIN_MSGMAP_ENTRY/消息映射表结构11UINTnMessage;/消息码12LRESULT(*pfn)(HWNDhWnd,UINTmessage,WPARAMwParam,LPARAMlParam);13;,79,13.2.7图形输出,例13.4,14#defineBEGIN_MESSAGE_MAP()conststructWIN_MSGMAP_ENTRY_messageEntries=15#defineON_MSG(nMessage,pfn)nMessage,pfn,16#defineEND_MESSAGE_MAP()0,NULL;17/消息处理函数原型-18LRESULTOnPaint(HWNDhWnd,UINTmessage,WPARAMwParam,LPARAMlParam);19/消息映射表宏定义-20BEGIN_MESSAGE_MAP()21ON_MSG(WM_PAINT,OnPaint)/重绘消息映射22END_MESSAGE_MAP()23/窗口过程-24LRESULTCALLBACKWndProc(HWNDhWnd,UINTmessage,WPARAMwParam,LPARAMlParam)25,80,13.2.7图形输出,例13.4,26WORDi;27for(i=0;_messageEntriesi.nMessage;i+)28/如果消息映射表中有该消息,则调用对应的消息处理函数29if(message=_messageEntriesi.nMessage)30if(message!=WM_DESTROY)/非WM_DESTROY消息处理后立即返回31return(*_messageEntriesi.pfn)(hWnd,message,wParam,lParam);32/如果是WM_DESTROY消息处理但不返回,继续后处理33(*_messageEntriesi.pfn)(hWnd,message,wParam,lParam);34break;353637if(message=WM_DESTROY)/WM_DESTROY后处理38PostQuitMessage(0);/发出WM_QUIT消息,结束应用程序,81,13.2.7图形输出,例13.4,39return0;/处理了这条消息必须返回04041returnDefWindowProc(hWnd,message,wParam,lParam);/其他消息调用默认处理4243/注册窗口类-44ATOMMyRegisterClass(HINSTANCEhInstance)4546WNDCLASSEXwcex;47wcex.cbSize=sizeof(WNDCLASSEX);48wcex.style=CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;49wcex.lpfnWndProc=(WNDPROC)WndProc;/设置主窗口过程50wcex.cbClsExtra=0;51wcex.cbWndExtra=0;52wcex.hInstance=hInstance;/应用程序实例,82,13.2.7图形输出,例13.4,53wcex.hIcon=LoadIcon(hInstance,(LPCTSTR)IDI_APP);54wcex.hCursor=LoadCursor(NULL,IDC_ARROW);55wcex.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);56wcex.lpszMenuName=(LPCSTR)IDR_APP;/主窗口主菜单57wcex.lpszClassName=szWindowClass;/主窗口类名58wcex.hIconSm=LoadIcon(hInstance,(LPCTSTR)IDI_APPSMALL);59returnRegisterClassEx(/保存应用程序实例,83,13.2.7图形输出,例13.4,66hMainWnd=CreateWindow(szWindowClass,szWindowTitle,ds,CW_USEDEFAULT,0,750,300,NULL,NULL,hInstance,NULL);/创建主窗口67if(!hMainWnd)returnFALSE;68ShowWindow(hMainWnd,nCmdShow);/显示主窗口69UpdateWindow(hMainWnd);/更新主窗口70returnTRUE;7172/消息循环-73intRun()/消息循环7475MSGmsg;76HACCELhAccelTable;77hAccelTable=LoadAccelerators(hInst,(LPCTSTR)IDR_APP);/加载快捷键资源78while(GetMessage(/进入消息循环9394/消息处理函数实现-95#definePI3.141592696LRESULTOnPaint(HWNDhWnd,UINTmessage,WPARAMwParam,LPARAMlParam)97/重绘消息处理98PAINTSTRUCTps;99HBRUSHhbr,hOldbr;100HPENhPen,hOldPen;101HBITMAPhBmp,hOldBmp;102BITMAPbm;103HDChdc,hdcMem;104RECTrt;105inti,mx,my,r=100;,86,13.2.7图形输出,例13.4,106intlnstyle=PS_SOLID,PS_DASH,PS_DOT,PS_DASHDOT,PS_DASHDOTDOT;107intbrstyle=HS_BDIAGONAL,HS_CROSS,HS_DIAGCROSS,HS_FDIAGONAL,HS_HOR

温馨提示

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

评论

0/150

提交评论