• BeginPaint和GetDC有什么区别


    windows编程问题 

    第一种情况显示出来的字很正常。 
    case WM_PAINT: 
               gdc = BeginPaint (hwnd, &ps); 
               TextOut (gdc, 0, 0, s, strlen (s)); 
               EndPaint (hwnd, &ps); 
               break;
    第二种情况显示的字不停闪烁。 
    case WM_PAINT: 
               gdc = GetDC (hwnd); 
               TextOut (gdc, 0, 0, s, strlen (s)); 
               ReleaseDC (hwnd, gdc); 
               break; 

    请教两种函数的作用?

    BeginPaint() 和EndPaint() 可以删除消息队列中的WM_PAINT消息,并使无效区域有效。 
    GetDC()和ReleaseDC()并不删除也不能使无效区域有效,因此当程序跳出 WM_PAINT 时 ,无效区域仍然存在。系统就回不断发送WM_PAINT消息,于是程序不断处理WM_PAINT消息。

    BeginPaint、EndPaint会告诉GDI内部,这个窗口需要重画的地方已经重画了,这样WM_PAINT处理完返回给系统后,系统不会再重发WM_PAINT,而GetDC没有告诉系统这个窗口需要重画的地方已经画过,在你把程序返回给系统后,系统一直以为通知你的重画命令你还没有乖乖的执行或者执行出错,所以在消息空闲时,它还会不断地发WM_PAINT催促你画,导致程序卡死。

    无效区域 

    无效区域就是指需要重画的区域,无效的意思是:当前内容是旧的,过时的。 
    假设A是新弹出的一个对话框或被激活的现有对话框,A对话框置于原来的活动对话框B前面,造成对话框B的部分或全部被覆盖,当对话框A移开或关闭后,使对话框B原来被覆盖的地方重新可见。那部分被覆盖的地方就称为无效区域。 
    只有当一个窗口消息空闲时,系统才会抽空检查一下这个窗口的无效区域是否为非空(WM_PAINT的优先级是最低的。这也就是为什么系统很忙时窗口和桌面往往会出现变白、刷新不了、留拖拽痕迹等现象的原因),如果非空,系统就发送WM_PAINT。所以一定要用BeginPaint、EndPaint把无效区域设为空,否则WM_PAINT将一直被发送。

    为什么WINDOWS要提出无效区域的概念

    这是为了加速。 
    因为BeginPaint和EndPaint用到的设备描述符只会在当前的无效区域内绘画,在有效区域内的绘画会自动被过滤,大家都知道,WIN GDI的绘画速度是比较慢的,所以能节省一个象素就节省一个,不用吝啬,这样可以有效加快绘画速度。 
    可见BeginPaint、EndPaint是比较“被动”的,只在窗口新建时和被摧残时才重画。 
    而GetDC用于主动绘制,只要你指到哪,它就打到哪。它不加判断就都画上去,无效区域跟它没关系。对话框没被覆盖没被摧残,它很健康,系统没要求它重画,但开发者有些情况下需要它主动重画:比如一个定时换外观的窗口,这时候就要在WM_TIMER处理代码用GetDC。这时候再用BeginPaint、EndPaint的话,会因为无效区域为空,所有绘画操作都将被过滤掉。

    例如:

    PAINTSTRUCT ps; 
                  HDC hdc = BeginPaint(hWnd,&ps); 
                  //Create a DC that matches the device 
                  HDC hdcMem = CreateCompatibleDC(hdc); 
                  //Load the bitmap 
                  HANDLE hBmp= LoadImage(g_hInst_MainWnd,MAKEINTRESOURCE(IDB_MAINWND),IMAGE_BITMAP,0,0,0); 
                  //Select the bitmap into to the compatible device context 
                  HGDIOBJ hOldSel = SelectObject(hdcMem,hBmp); 
                  //Get the bitmap dimensions from the bitmap 
                  BITMAP bmp; 
                  GetObject(hBmp,sizeof(BITMAP),&bmp); 
                  //Get the window area 
                  RECT rc; 
                  GetClientRect(hWnd,&rc); 
                  //Copy the bitmap image from the memory DC to the screen DC 
                  BitBlt(hdc,rc.left,rc.top,bmp.bmWidth,bmp.bmHeight,hdcMem,0,0,SRCCOPY); 
                  //Restore original bitmap selection and destroy the memory DC 
                  SelectObject(hdcMem,hOldSel);     
                  DeleteDC(hdcMem); 
                  EndPaint(hWnd,&ps); 
                  return 0;

    下面是更加详细的介绍

    //======================================================================== 
    //TITLE: 
    //     EVC绘制位图--BeginPaint()与GetDC()的区别 
    //AUTHOR: 
    //     norains 
    //DATE: 
    //     Tuesday   29-August-2006 
    //======================================================================== 
    1.BeginPaint()和GetDC() 
             在EVC中绘制位图比较方便,有不少现成的函数可供调用,我们所要注意的只是BeginPaint()或GetDC()的使用即可. 
             因为代码比较简单,所以不做更多解释. 
             这是消息循环函数: 
             LRESULT CALLBACK MainWndProc(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam) 
             { 
                 ...... 
                 switch(wMsg) 
                 { 
                     case WM_PAINT: 
                             OnPaintMainWnd(hWnd,wMsg,wParam,lParam); 
                             break; 
                     ......                 
                 } 
                 return DefWindowProc(hWnd,wMsg,wParam,lParam); 
                 ...... 
             } 
             响应WM_PAINT消息的函数,在这里进行位图的绘制: 
             LRESULT OnPaintMainWnd(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam) 
             { 
                 PAINTSTRUCT ps; 
                 HDC hdc = BeginPaint(hWnd,&ps); 
                 //Create a DC that matches the device 
                 HDC hdcMem = CreateCompatibleDC(hdc); 
                 //Load the bitmap 
                 HANDLE hBmp= LoadImage(g_hInst_MainWnd,MAKEINTRESOURCE(IDB_MAINWND),IMAGE_BITMAP,0,0,0); 
                 //Select the bitmap into to the compatible device context 
                 HGDIOBJ hOldSel = SelectObject(hdcMem,hBmp); 
                 //Get the bitmap dimensions from the bitmap 
                 BITMAP bmp; 
                 GetObject(hBmp,sizeof(BITMAP),&bmp); 
                 //Get the window area 
                 RECT rc; 
                 GetClientRect(hWnd,&rc); 
                 //Copy the bitmap image from the memory DC to the screen DC 
                 BitBlt(hdc,rc.left,rc.top,bmp.bmWidth,bmp.bmHeight,hdcMem,0,0,SRCCOPY); 
                 //Restore original bitmap selection and destroy the memory DC 
                 SelectObject(hdcMem,hOldSel);     
                 DeleteDC(hdcMem); 
                 EndPaint(hWnd,&ps); 
                 return 0; 
             } 
     我们都知道BeginPaint()和EndPaint()需要配套使用,并且这两个函数也只能用在WM_PAINT消息的相应函数当中.如果我们在WM_PAINT的响应函数中将以上两个绘制函数相应替换为GetDC()和ReleaseDC()会有什么结果呢?
    即: 
             HDC hdc = BeginPaint(hWnd,&ps);     -->    HDC hdc = GetDC(hWnd); 
             EndPaint(hWnd,&ps);                 -->    ReleaseDC(hWnd,hdc); 
             编译并运行程序,我们发现窗口一片空白,好像没有绘制位图.但其实不尽然,我们采用单步调试,可以发现其实位图已经绘制出来,只不过又被背景颜色抹掉了.由此可知,如果需要使用GetDC(),我们对消息循环函数必须要加上对WM_ERASEBKGND的处理: 

    LRESULT CALLBACK MainWndProc(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam) 
             { 
                 switch(wMsg) 
                 { 
                     case WM_PAINT: 
                             OnPaintMainWnd(hWnd,wMsg,wParam,lParam); 
                             break; 
                     case WM_ERASEBKGND     
                             return 0;             
                 } 
                 return DefWindowProc(hWnd,wMsg,wParam,lParam); 
             } 
    只要系统不对WM_ERASEBKGND进行默认处理,我们用GetDC()替代BeginPaint()就可以正常使用. 
    至此我们可以看出BeginPaint(),EndPaint()和GetDC(),ReleaseDC()的区别.前一对只能用在WM_PAINT响应函数中,并且绘制背景时不会被抹掉;后一对随处可用,但如果用在WM_PAINT响应函数中,那么接下来将会被WM_ERASEBKGND消息的响应函数的背景绘制给抹掉. 

    绘图闪烁问题

    有时候我们大量绘制屏幕时,可能会出现屏幕闪烁问题,这时候可以采用双缓冲的做法.步骤首先是创建一个内存DC,然后往内存DC中绘图,最后把内存DC的内容复制到显示DC中,完成绘制.具体过程并不复杂,结合代码来说明一下.
    PS:这段代码也是相应WM_PAINT 消息的.

    PAINTSTRUCT ps; 
         HDC hdc; 
         //获取屏幕显示DC         
         hdc = BeginPaint (hWnd, &ps); 
         //创建内存DC 
         HDC hdcMem = CreateCompatibleDC(hdc); 
         //创建一个bmp内存空间 
         HBITMAP hBmp = CreateCompatibleBitmap(hdc,SCREEN_WIDTH,SCREEN_HEIGHT); 
         //将bmp内存空间分配给内存DC 
         HGDIOBJ hOldSel = SelectObject(hdcMem,hBmp); 
         //这是使用者需要绘制的画面,全部往内存DC绘制 
         Rectangle(hdcMem,0,0,SCREEN_WIDTH,SCREEN_HEIGHT); 
         DrawMenuButton(hdcMem); 
         //将内存DC的内容复制到屏幕显示DC中,完成显示 
         BitBlt(hdc,0,0,SCREEN_WIDTH,SCREEN_HEIGHT,hdcMem,0,0,SRCCOPY); 
         //清除资源 
         SelectObject(hdcMem,hOldSel);     
         DeleteDC(hdcMem);     
         EndPaint(hWnd,&ps);


  • 相关阅读:
    随手记十——淘宝静态页面
    随手记九——溢出文字处理、背景图片填充、图片代替文字
    随手记八——关于伪元素和仿淘宝导航栏
    随手记七——关于float的一个上节没明白的问题
    随手记六——两个经典BUG和bfc
    随手记五——盒子模型和层模型
    随手记四——一些课堂笔记和小技巧、总结
    随手记三——理解相邻兄弟选择器的辛酸过程
    随手记二——CSS样式和选择器
    jQuery实现手风琴效果
  • 原文地址:https://www.cnblogs.com/furzoom/p/7710306.html
Copyright © 2020-2023  润新知