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);
BeginPaint和GetDC有什么区别的更多相关文章
- BeginPaint 和 GetDC 的一个区别
这个问题是在做9*9乘法表这个课后习题发现的-- 先给出我的结论:注意在 WM_PAINT 下不要使用hdc = GetDC(hwnd)的方式,因为这样会不停的触发WM_PAINT消息! 东西看上去就 ...
- BeginPaint/EndPaint(CPaintDC)与GetDC(CClientDC)的区别
在OnPaint函数中,用CClientDC dc(this)代替CPaintDC(this)后,界面不断闪烁. 说明:CClientDC是对GetDC的使用封装, CPaintDC是对BeginPa ...
- GDI编程
图形设备接口(GDI)是一个可执行程序,它接受Windows应用程序的绘图请求(表现为GDI函数调用),并将它们传给相应的设备驱动程序,完成特定于硬件的输出,象打印机输出和屏幕输出.GDI负责Wind ...
- VC++学习之GDI概述
VC++学习之GDI概述 图形设备接口(GDI)是一个可执行程序,它接受Windows应用程序的绘图请求(表现为GDI函数调用),并将它们传给相应的设备驱动程序,完成特定于硬件的输出,象打印机输出和屏 ...
- VC++知识点整理
1.内联函数 定义:定义在类体内的成员函数,即函数的函数体放在类体内 特点:在调用处用内联函数体的代码来替换,用于解决程序的运行效率问题.一定要在调用之前定义,并且内联函数 ...
- DC、CDC及CDC的各个子类
设备描述表是一个包含设备信息的结构体(物理设备如显示器.打印机),MFC中关于图像操作都需要DC来完成.HDC是Windows的一种数据类型,是设备描述句柄:CDC是MFC封装的Windows 设 ...
- GDI编程小结
图形设备接口(GDI)是一个可运行程序,它接受Windows应用程序的画图请求(表现为GDI函数调用),并将它们传给对应的设备驱动程序,完毕特定于硬件的输出,象打印机输出和屏幕输出.GDI负责Wind ...
- GetDc函数与GetWindowDC函数的区别
GetDc函数:用于获得hWnd参数所指定窗口的客户区域的一个设备环境 GetWindowDC函数:返回hWnd参数所指定的窗口的设备环境. 获得的设备环境覆盖了整个窗口(包括非客户区),例如标题栏. ...
- CDC和HDC的区别与转换
CDC和HDC的区别与转换 一.区别与联系HDC是句柄:CDC是MFC封装的Windows 设备相关的一个类:CClientDC是CDC的衍生类,产生对应于Windows客户区的对象HDC是WIN ...
随机推荐
- 将输入流InputStream转换为String
public static String convertStreamToString(InputStream is) { /* * To convert the InputStream to Stri ...
- mysql经常使用查询:group by,左连接,子查询,having where
前几天去了两个比較牛的互联网公司面试.在sql这块都遇到问题了,哎.可惜呀,先把简单的梳理一下 成绩表 score 1.group by 使用 按某一个维度进行分组 比如: 求每一个同学的总分 SEL ...
- Controller层返回字符串
刚开始练习,有时候想让Controller层返回一个字符串,但是他却去寻找这个字符串名字的jsp页面,结果肯定会是404的,研究了一会才明白过来,如果Controller需要返回一个值的话,需要再方法 ...
- StringBuilder作用
String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然 ...
- (webstorm的CSS插件)前端开发必备!Emmet使用手册
介绍 Emmet (前身为 Zen Coding) 是一个能大幅度提高前端开发效率的一个工具: 基本上,大多数的文本编辑器都会允许你存储和重用一些代码块,我们称之为“片段”.虽然片段能很好地推动你得生 ...
- Maven上传本地jar
1. 将Jar包安装到本地仓库 -- DgroupId和DartifactId构成了该jar包在pom.xml的坐标, 对应依赖的DgroupId和DartifactId -- Dfile表示需 ...
- FTPHelper类
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.N ...
- Net中的代码规范工具及使用
Net中的代码规范工具及使用 https://www.cnblogs.com/selimsong/p/9209254.html 上一篇文章介绍了编码标准中一些常用的工具,本篇就具体来介绍如何使用它们来 ...
- eclipse maven 刷新报错
问题描述: An internal error occurred during: "Loading descriptor for cmbc_wms.".java.lang.Null ...
- Windows下Nginx+Web.py+FastCGI服务搭建
在搭建之前,有必要了解下什么是fastcgi,但鉴于我自己也不大了解,这里就不搬门弄斧了,请参考各种百科和官网资料. 1.资源下载 python下载地址:戳这里webpy下载地址:戳这里flup下载地 ...