转自:http://hi.baidu.com/d_b_mike/blog/item/ec8820d0fb9127d5572c84a9.html

这是个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的话,会因为无效区域为空,所有绘画操作都将被过滤掉。

eg:

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消息的响应函数 的背景绘制给抹掉.
       
       
       
       
2.绘图闪烁问题       
     有时候我们大量绘制屏幕时,可能会出现屏幕闪烁问题,这时候可以采用双缓冲的做法.步骤首先是创建一个内存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);

转载于:https://www.cnblogs.com/cdfyanghua/archive/2009/10/11/1580835.html

BeginPaint和GetDC有什么区别?【转】相关推荐

  1. BeginPaint和GetDC有什么区别

    windows编程问题 第一种情况显示出来的字很正常. case WM_PAINT: gdc = BeginPaint (hwnd, &ps); TextOut (gdc, 0, 0, s, ...

  2. VC绘制位图--BeginPaint()与GetDC()的区别

    //======================================================================== //TITLE: //    EVC绘制位图--B ...

  3. BeginPaint和GetDC的区别

    BeginPaint和GetDC的区别 代码 unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Gr ...

  4. Beginpaint 与 GetDC 的区别

    InvalidateRect是一个函数,该函数向指定的窗体更新区域添加一个矩形,然后窗体跟新区域的这一部分将被重新绘制. BeginPaint.EndPaint是比较"被动"的,只 ...

  5. BeginPaint EndPaint 与GetDC ReleaseDC的区别

    1. 绘图一般在WM_PAINT消息里面绘图, 一般用BeginPaint( HWND hwnd, LPPAINTSTRUCT lpPaint) 与BOOL EndPaint(   HWND hWnd ...

  6. BeginPaint和GetDC

    使用方法: BeginPaint hdc = BeginPaint (hwnd, &ps): // 使用GDI函数 EndPaint (hwnd, &ps); GetDC hdc = ...

  7. Win32中BeginPaint和GetDC的使用

    这是正确的方式,重要的事情说三遍 WM_PAINT: {...hdc = BeginPaint(hWnd, &ps);//hdc = GetDC(hWnd); ... } 1.单独使用GetD ...

  8. java getdc_GetWindowDC-BeginPaint-GetDC 区别详解

    1. BeginPaint和EndPaint用在WM_PAINT消息处理当中:GetDC可以在处理非WM_PAINT消息时获取设备描述表句柄. 2. BeginPaint返回的设备描述表句柄只能在PA ...

  9. 可视化GDI操作题目

    1.GDI是什么的英文缩写? Graphics Device Interface 2.什么是设备的无关性? 操作系统屏蔽了硬件设备的差异 3.GDI的主要任务是什么?起到什么样的作用? 主要任务:负责 ...

最新文章

  1. 数据结构:基数排序(Radix sort)
  2. 微软为什么要“杀死”小娜?
  3. hibernate 表关系映射详解之继承关系
  4. 如何掌握java API的方法
  5. 企业实战_13_MyCat清除冗余数据
  6. 应用程序_构建应用程序12 条参考准则
  7. Java编写敏感词过滤程序
  8. google 搜索接口
  9. 为什么 MongoDB 索引选择B-树,而 Mysql 选择B+树(精干总结)
  10. VM虚拟机Ubuntu系统鼠标闪烁通用解决办法
  11. Wi-Fi:802.11 物理层和发射机测量概述
  12. 「Android基于MQTT实现消息通知」
  13. android 跳转腾讯地图导航,Android 跳转到百度、高德、腾讯地图导航
  14. 微信小程序 canvas 分享图片 生成图片
  15. android目录结构
  16. U盘在自己电脑读不出来,但其它电脑的可以读,别的u盘在自己电脑又可以识别的解决方法
  17. linux显卡驱动安全模式,Win7怎么在安全模式下安装显卡驱动?
  18. 使用 Amazon SageMaker JumpStart 更轻松地在组织内共享 ML 模型和笔记本
  19. 教训总结(持续更新中)
  20. 通用Windows驱动程序设计原则DCHU

热门文章

  1. opencv-api contourArea
  2. java自定义按钮代码_用于短代码的WP Tiny MCE帖子编辑器上的自定义按钮
  3. mysql proxy 读写分离_mysql-proxy 实现读写分离
  4. Java基础学习总结(153)——HashMap、Hashtable、ConcurrentHashMap的原理与区别
  5. Java设计模式学习总结(11)——结构型模式之装饰器模式
  6. 生产上线发现重大Bug的思考
  7. 计算机基础知识背诵口诀,内部资料--教育基础知识背诵口诀(一遍记住)
  8. java中的static类_再议Java中的static关键字
  9. saslauthd mysql_Postfix,saslauthd,mysql,smtp身份验证问题
  10. app头像上传vue_当前GitHub上排名前十的热门Vue项目