windows编程问题

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

  1. case WM_PAINT:
  2. gdc = BeginPaint (hwnd, &ps);
  3. TextOut (gdc, 0, 0, s, strlen (s));
  4. EndPaint (hwnd, &ps);
  5. break;

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

  1. case WM_PAINT:
  2. gdc = GetDC (hwnd);
  3. TextOut (gdc, 0, 0, s, strlen (s));
  4. ReleaseDC (hwnd, gdc);
  5. 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的话,会因为无效区域为空,所有绘画操作都将被过滤掉。

例如:

  1. PAINTSTRUCT ps;
  2. HDC hdc = BeginPaint(hWnd,&ps);
  3. //Create a DC that matches the device
  4. HDC hdcMem = CreateCompatibleDC(hdc);
  5. //Load the bitmap
  6. HANDLE hBmp= LoadImage(g_hInst_MainWnd,MAKEINTRESOURCE(IDB_MAINWND),IMAGE_BITMAP,0,0,0);
  7. //Select the bitmap into to the compatible device context
  8. HGDIOBJ hOldSel = SelectObject(hdcMem,hBmp);
  9. //Get the bitmap dimensions from the bitmap
  10. BITMAP bmp;
  11. GetObject(hBmp,sizeof(BITMAP),&bmp);
  12. //Get the window area
  13. RECT rc;
  14. GetClientRect(hWnd,&rc);
  15. //Copy the bitmap image from the memory DC to the screen DC
  16. BitBlt(hdc,rc.left,rc.top,bmp.bmWidth,bmp.bmHeight,hdcMem,0,0,SRCCOPY);
  17. //Restore original bitmap selection and destroy the memory DC
  18. SelectObject(hdcMem,hOldSel);
  19. DeleteDC(hdcMem);
  20. EndPaint(hWnd,&ps);
  21. return 0;

下面是更加详细的介绍

  1. //========================================================================
  2. //TITLE:
  3. // EVC绘制位图--BeginPaint()与GetDC()的区别
  4. //AUTHOR:
  5. // norains
  6. //DATE:
  7. // Tuesday 29-August-2006
  8. //========================================================================
  9. 1.BeginPaint()和GetDC()
  10. EVC中绘制位图比较方便,有不少现成的函数可供调用,我们所要注意的只是BeginPaint()或GetDC()的使用即可.
  11. 因为代码比较简单,所以不做更多解释.
  12. 这是消息循环函数:
  13. LRESULT CALLBACK MainWndProc(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam)
  14. {
  15. ......
  16. switch(wMsg)
  17. {
  18. case WM_PAINT:
  19. OnPaintMainWnd(hWnd,wMsg,wParam,lParam);
  20. break;
  21. ......
  22. }
  23. return DefWindowProc(hWnd,wMsg,wParam,lParam);
  24. ......
  25. }
  26. 响应WM_PAINT消息的函数,在这里进行位图的绘制:
  27. LRESULT OnPaintMainWnd(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam)
  28. {
  29. PAINTSTRUCT ps;
  30. HDC hdc = BeginPaint(hWnd,&ps);
  31. //Create a DC that matches the device
  32. HDC hdcMem = CreateCompatibleDC(hdc);
  33. //Load the bitmap
  34. HANDLE hBmp= LoadImage(g_hInst_MainWnd,MAKEINTRESOURCE(IDB_MAINWND),IMAGE_BITMAP,0,0,0);
  35. //Select the bitmap into to the compatible device context
  36. HGDIOBJ hOldSel = SelectObject(hdcMem,hBmp);
  37. //Get the bitmap dimensions from the bitmap
  38. BITMAP bmp;
  39. GetObject(hBmp,sizeof(BITMAP),&bmp);
  40. //Get the window area
  41. RECT rc;
  42. GetClientRect(hWnd,&rc);
  43. //Copy the bitmap image from the memory DC to the screen DC
  44. BitBlt(hdc,rc.left,rc.top,bmp.bmWidth,bmp.bmHeight,hdcMem,0,0,SRCCOPY);
  45. //Restore original bitmap selection and destroy the memory DC
  46. SelectObject(hdcMem,hOldSel);
  47. DeleteDC(hdcMem);
  48. EndPaint(hWnd,&ps);
  49. return 0;
  50. }

我们都知道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的处理:

  1. LRESULT CALLBACK MainWndProc(HWND hWnd,UINT wMsg,WPARAM wParam,LPARAM lParam)
  2. {
  3. switch(wMsg)
  4. {
  5. case WM_PAINT:
  6. OnPaintMainWnd(hWnd,wMsg,wParam,lParam);
  7. break;
  8. case WM_ERASEBKGND
  9. return 0;
  10. }
  11. return DefWindowProc(hWnd,wMsg,wParam,lParam);
  12. }

只要系统不对WM_ERASEBKGND进行默认处理,我们用GetDC()替代BeginPaint()就可以正常使用. 

至此我们可以看出BeginPaint(),EndPaint()和GetDC(),ReleaseDC()的区别.前一对只能用在WM_PAINT响应函数中,并且绘制背景时不会被抹掉;后一对随处可用,但如果用在WM_PAINT响应函数中,那么接下来将会被WM_ERASEBKGND消息的响应函数的背景绘制给抹掉.

绘图闪烁问题

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

PS:这段代码也是相应WM_PAINT 消息的.

  1. PAINTSTRUCT ps;
  2. HDC hdc;
  3. //获取屏幕显示DC
  4. hdc = BeginPaint (hWnd, &ps);
  5. //创建内存DC
  6. HDC hdcMem = CreateCompatibleDC(hdc);
  7. //创建一个bmp内存空间
  8. HBITMAP hBmp = CreateCompatibleBitmap(hdc,SCREEN_WIDTH,SCREEN_HEIGHT);
  9. //将bmp内存空间分配给内存DC
  10. HGDIOBJ hOldSel = SelectObject(hdcMem,hBmp);
  11. //这是使用者需要绘制的画面,全部往内存DC绘制
  12. Rectangle(hdcMem,0,0,SCREEN_WIDTH,SCREEN_HEIGHT);
  13. DrawMenuButton(hdcMem);
  14. //将内存DC的内容复制到屏幕显示DC中,完成显示
  15. BitBlt(hdc,0,0,SCREEN_WIDTH,SCREEN_HEIGHT,hdcMem,0,0,SRCCOPY);
  16. //清除资源
  17. SelectObject(hdcMem,hOldSel);
  18. DeleteDC(hdcMem);
  19. EndPaint(hWnd,&ps);

BeginPaint和GetDC有什么区别的更多相关文章

  1. BeginPaint 和 GetDC 的一个区别

    这个问题是在做9*9乘法表这个课后习题发现的-- 先给出我的结论:注意在 WM_PAINT 下不要使用hdc = GetDC(hwnd)的方式,因为这样会不停的触发WM_PAINT消息! 东西看上去就 ...

  2. BeginPaint/EndPaint(CPaintDC)与GetDC(CClientDC)的区别

    在OnPaint函数中,用CClientDC dc(this)代替CPaintDC(this)后,界面不断闪烁. 说明:CClientDC是对GetDC的使用封装, CPaintDC是对BeginPa ...

  3. GDI编程

    图形设备接口(GDI)是一个可执行程序,它接受Windows应用程序的绘图请求(表现为GDI函数调用),并将它们传给相应的设备驱动程序,完成特定于硬件的输出,象打印机输出和屏幕输出.GDI负责Wind ...

  4. VC++学习之GDI概述

    VC++学习之GDI概述 图形设备接口(GDI)是一个可执行程序,它接受Windows应用程序的绘图请求(表现为GDI函数调用),并将它们传给相应的设备驱动程序,完成特定于硬件的输出,象打印机输出和屏 ...

  5. VC++知识点整理

    1.内联函数        定义:定义在类体内的成员函数,即函数的函数体放在类体内        特点:在调用处用内联函数体的代码来替换,用于解决程序的运行效率问题.一定要在调用之前定义,并且内联函数 ...

  6. DC、CDC及CDC的各个子类

      设备描述表是一个包含设备信息的结构体(物理设备如显示器.打印机),MFC中关于图像操作都需要DC来完成.HDC是Windows的一种数据类型,是设备描述句柄:CDC是MFC封装的Windows 设 ...

  7. GDI编程小结

    图形设备接口(GDI)是一个可运行程序,它接受Windows应用程序的画图请求(表现为GDI函数调用),并将它们传给对应的设备驱动程序,完毕特定于硬件的输出,象打印机输出和屏幕输出.GDI负责Wind ...

  8. GetDc函数与GetWindowDC函数的区别

    GetDc函数:用于获得hWnd参数所指定窗口的客户区域的一个设备环境 GetWindowDC函数:返回hWnd参数所指定的窗口的设备环境. 获得的设备环境覆盖了整个窗口(包括非客户区),例如标题栏. ...

  9. CDC和HDC的区别与转换

    CDC和HDC的区别与转换 一.区别与联系HDC是句柄:CDC是MFC封装的Windows   设备相关的一个类:CClientDC是CDC的衍生类,产生对应于Windows客户区的对象HDC是WIN ...

随机推荐

  1. 将输入流InputStream转换为String

    public static String convertStreamToString(InputStream is) { /* * To convert the InputStream to Stri ...

  2. mysql经常使用查询:group by,左连接,子查询,having where

    前几天去了两个比較牛的互联网公司面试.在sql这块都遇到问题了,哎.可惜呀,先把简单的梳理一下 成绩表 score 1.group by 使用 按某一个维度进行分组 比如: 求每一个同学的总分 SEL ...

  3. Controller层返回字符串

    刚开始练习,有时候想让Controller层返回一个字符串,但是他却去寻找这个字符串名字的jsp页面,结果肯定会是404的,研究了一会才明白过来,如果Controller需要返回一个值的话,需要再方法 ...

  4. StringBuilder作用

    String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然 ...

  5. (webstorm的CSS插件)前端开发必备!Emmet使用手册

    介绍 Emmet (前身为 Zen Coding) 是一个能大幅度提高前端开发效率的一个工具: 基本上,大多数的文本编辑器都会允许你存储和重用一些代码块,我们称之为“片段”.虽然片段能很好地推动你得生 ...

  6. Maven上传本地jar

    1. 将Jar包安装到本地仓库 -- DgroupId和DartifactId构成了该jar包在pom.xml的坐标, 对应依赖的DgroupId和DartifactId    -- Dfile表示需 ...

  7. FTPHelper类

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.N ...

  8. Net中的代码规范工具及使用

    Net中的代码规范工具及使用 https://www.cnblogs.com/selimsong/p/9209254.html 上一篇文章介绍了编码标准中一些常用的工具,本篇就具体来介绍如何使用它们来 ...

  9. eclipse maven 刷新报错

    问题描述: An internal error occurred during: "Loading descriptor for cmbc_wms.".java.lang.Null ...

  10. Windows下Nginx+Web.py+FastCGI服务搭建

    在搭建之前,有必要了解下什么是fastcgi,但鉴于我自己也不大了解,这里就不搬门弄斧了,请参考各种百科和官网资料. 1.资源下载 python下载地址:戳这里webpy下载地址:戳这里flup下载地 ...