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

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);
         }
         //        
         至此我们可以看出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);

posted on 2009-11-25 14:51 过河的小兵 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/eddyshn/archive/2009/11/25/1610532.html

BeginPaintGetDc(转)相关推荐

最新文章

  1. 关于进程间通信的学习心得
  2. mysql 数据目录更改
  3. 【KEIL·单片机·扫盲贴】关于ARM单片机程序内存使用情况的细致讨论。
  4. java runnable 异常_JAVA 线程中的异常捕获
  5. kibana 更新 索引模式_Kibana对索引动态加字段显示
  6. select函数_SQL高级功能:窗口函数
  7. 在WCF中启用事务的6个步骤
  8. HTML鼠标悬停显示隐藏div,javascript – 在鼠标悬停时显示/隐藏DIV
  9. 自动驾驶—— Image Caption的学习笔记(legacy)
  10. 容器和 批量删除 镜像_更高更快更稳,看阿里巴巴如何修炼容器服务「内外功」...
  11. 列表推导式 生成器表达式
  12. java list stream avg_Java8之list.stream的常见使用
  13. openssh常用命令记录
  14. 电动自行车出租管理系统VS开发sqlserver数据库web结构c#编程计算机网页
  15. 阿里云OSS前端直传踩坑
  16. 《电子元器件的可靠性》——3.6节恒定应力加速寿命试验
  17. GP数据库锁表如何解锁
  18. 用matlab产生chu序列和frank序列
  19. 工业相机的曝光时间和帧率的关系
  20. android+apk+自动安装,Android版本更新下载apk自动安装的方法

热门文章

  1. 万网mysql连接_[转载]如何远程连接万网的mysql数据库?
  2. python圣经 github_GitHub标星6000+!Python带你实践机器学习圣经PRML
  3. 学校wifi需要认证登录怎么解决
  4. php 枚举类代替hard code代码
  5. DBA数据库管理员要求
  6. Ultral 做系统盘 记录
  7. 在Ubuntu下使用opencv调用海康威视的网络摄像头
  8. Mac上好用的压缩软件,你值得拥有
  9. vba 服务器上删除文件夹,如何删除文件夹-Excel VBA程序开发-ExcelHome技术论坛 -
  10. 职称评审专业技术工作总结,这么写更易通过!