BeginPaint和GetDC的区别


这是个windows编程问题。

BeginPaint和GetDC的区别

第一种情况显示出来的字很正常。

********************************************************************************
    caseWM_PAINT:
         gdc = BeginPaint (hwnd, &ps);
         TextOut (gdc, 0, 0, s, strlen (s));
         EndPaint (hwnd, &ps);
    break;

*******************************************************************************

第二种情况显示的字不停闪烁。

*******************************************************************************
   caseWM_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消息。

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

【无效区域】

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

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

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

***********************************************************************************************************************************

eg:

  1. PAINTSTRUCT ps;
  2. HDC hdc = Beginpaint(hwnd, &ps);
  3. HDC hdcMem = CreateCompatibleDC(hdc); //Create a DC that matches the device
  4. HANDLE hBmp = LoadImage(g_hInst_MainWnd, MAKEINTRESOURCE(IDB_MAINWND),
  5.                             IMAGE_BITMAP, 0, 0, 0);
  6. HGDIOBJ hOldSel = SelectObject(hdcMem, hBmp); //Select the bitmap into to the compatible
  7.                                    //device context
  8. BITMAP bmp; //Get the bitmap dimensions from the bitmap
  9. GetObject(hBmp, sizeof(BIMAP), &bmp);
  10. RECT rc;        //Get the window area
  11. GetClientRect(hwnd, &rc);
  12. //Copy the bitmap image from the memory DC to the screen DC
  13. BitBlt(hdc, rc.left, rc.top, bmp.bmWidth, bmp.bmHeight, hdcMem, 0, 0, SRCCOPY);
  14. SelectObject(hdcMem, hOldSel); //Restore original bitmap selection and destroy
  15.                       //the memory DC
  16. DeleteDC(hdcMem);
  17. EndPaint(hWnd, &ps);
  18. 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);
                 HDC hdcMem = CreateCompatibleDC(hdc);//Create a DC that matches the device             
                HANDLE hBmp= LoadImage(g_hInst_MainWnd,MAKEINTRESOURCE
                                                         (IDB_MAINWND),IMAGE_BITMAP,0,0,0); //Load the bitmap
                   //Select the bitmap into to the compatible device context
                HGDIOBJ hOldSel = SelectObject(hdcMem,hBmp);
                 BITMAP bmp;   //Get the bitmap dimensions from the bitmap
                GetObject(hBmp,sizeof(BITMAP),&bmp);
                RECT rc;          //Get the window area
                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);
                SelectObject(hdcMem,hOldSel);//Restore original bitmap selection and destroy the memory
                                                                   //DC    
                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;           
     hdc = BeginPaint (hWnd, &ps);
//获取屏幕显示DC  
     HDC hdcMem = CreateCompatibleDC(hdc); //创建内存DC
            //创建一个bmp内存空间
     HBITMAP hBmp = CreateCompatibleBitmap(hdc,SCREEN_WIDTH,SCREEN_HEIGHT);
     HGDIOBJ hOldSel = SelectObject(hdcMem,hBmp);
   //将bmp内存空间分配给内存DC
           //这是使用者需要绘制的画面,全部往内存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);

 

时间: 2024-10-01 17:58:51

BeginPaint和GetDC的区别的相关文章

设备上下文-请问各位大神,Windows编程里边的DC(device context)到底是什么啊?

问题描述 请问各位大神,Windows编程里边的DC(device context)到底是什么啊? 请教各位大神,设备上下文(device context)到底是个什么东西?它仅仅是一个抽象概念还是一个实体概念(即有对应的代码)?它是一个结构体吗?如果它有对应的源码的话,怎么能找到?在下在网上找了很多资料,包括MSDN上的,但越看越糊涂.在下想了解关于它最本质的东西,在下怎么才能"看到它"?这个问题给在下带来很大困惑,希望大家为在下指点迷津,拜托大家了!在下先行谢过! 解决方案 DC实

VC中CDC、HDC、pDC区别与联系及相互转换_C 语言

1.CDC *pDC和HDC hdc有什么不同,类似的有CWnd *pWnd和HWnd? pDC是类指针 HDC是windows句柄 通过pDC获得hdc: HDC hdc=pDC->GetSafeHdc(); 通过hdc获得pDC: CDC *pDC=new CDC; pDC->Attach(hdc); 2.hDC和CDC有本质区别 HDC是WINDOWS的一种数据类型,是设备描述句柄.而CDC是MFC里的一个类,它封装了几乎所有的关于HDC的操作.也可以这样说,HDC定义的变量指向一块内存

mfc-LBN_SELCHANGE和LBN_DBLCLK有什么区别?

问题描述 LBN_SELCHANGE和LBN_DBLCLK有什么区别? LBN_SELCHANGE和LBN_DBLCLK有什么区别呢,我是新手,请说的详细些. 解决方案 一个在选择更改的时候触发,一个在双击的时候触发 解决方案二: msdn文档中都有,详细地自己看,或者google下

固态硬盘做系统盘和做缓存盘有什么区别

  固态硬盘做系统盘和做缓存盘有什么区别          用固态硬盘直接做缓存盘不同于直接用固态硬盘做系统盘直接在固态硬盘上读取数据,固态硬盘做缓存盘的时候是根据用户经常访问的数据,将这一部分数据保存到固态硬盘上方便下次读取的时候快速读取而已,其作用类似硬盘的内存,只不过这块内存的数据并不会伴随关机而自动清空.         推荐阅读:让SSD速度飞起来 固态硬盘优化技巧大全  因此综上所述,最立竿见影的方法就是直接将固态硬盘做系统盘,并用剩余的容量安装游戏或者其他常用软件,这样收益是最明显

[数据结构] 数组与链表的优缺点和区别

概述 数组 是将元素在内存中连续存放,由于每个元素占用内存相同,可以通过下标迅速访问数组中任何元素.但是如果要在数组中增加一个元素,需要移动大量元素,在内存中空出一个元素的空间,然后将要增加的元素放在其中.同样的道理,如果想删除一个元素,同样需要移动大量元素去填掉被移动的元素.如果应用需要快速访问数据,很少插入和删除元素,就应该用数组. 链表 中的元素在内存中不是顺序存储的,而是通过存在元素中的指针联系到一起,每个结点包括两个部分:一个是存储 数据元素 的 数据域,另一个是存储下一个结点地址的

关于支付系统中的同步通知和异步通知电商的区别,为什么需要通知

问题描述 关于支付系统中的同步通知和异步通知电商的区别,为什么需要通知 在电商对应的支付系统中当支付完成之后需要做相关的同步通知和异步通知操作,请大神解释一下什么是同步通知和异步通知,为什么需要同步通知和异步通知. 解决方案 同步用于即时通知支付完成 异步用于防止信息漏发漏收 解决方案二: 可以这样理解, 1.用户(买家)支付完成后,电商平台需要实时的给用户一个通知,如支付已经处理等待订单确认. 2.电商平台,这块就需要考虑系统技术方面的各个环节,考虑应对复杂多变的并发用户量.业务.流量.网络环

nil、Nil、NULL和NSNull区别

前言 记得曾经有不少朋友问过笔者,在Objective-C中nil和Nil以及NULL的区别.最重要的是,在面试中还有不少朋友常会被问到.记得当年刚找工作的时候,笔者就被面试官问到过,现在笔者在这里统一详细说明. NULL 对于学习过C/C++语言的朋友,对NULL一定很熟悉吧?这就是在C/C++中的空指针. 在C语言中,NULL是无类型的,只是一个宏,它代表空.我们不研究C++中的NULL,因为在C++11以后又有了新的定义,我们不深究. 这就是C语言中所谓的NULL(C++的定义比较复杂,这

xcode-Xcode和ObjectiveC有什么区别

问题描述 Xcode和ObjectiveC有什么区别 现在开发一个iosApp,用Xcode(Swift)好还是ObjectiveC好? 有什么优缺点? 解决方案 projectiveC还是Objective-C Objective-C是语言,XCode是苹果官方的编写工具,XCode里用的是Objective-C或swift 解决方案二: Xcode是编译器 Objective-C和Swift是语言

MathType正式版与精简版有什么区别

MathType正式版与精简版有什么区别   MathType 6.9启动界面示例 MathType正式版的功能与特点: 1.Office办公软件兼容使用,MathType 6.9版本在Windows 系统中完全兼容Office 2013和Office 365.Office 2010.2007.2003和XP等. 2.MathType在Word 2013.2010.2007.Word 2003和XP 2002中的菜单和工具栏. 插入公式:不管是否有公式编号,Word功能区的MathType选项卡