BeginPaint+EndPaint组合与GetDC用法区别与对比

来源:互联网 发布:域名备案年审 编辑:程序博客网 时间:2024/06/14 12:48
1.BeginPaint(HWND hwnd,PAINTSTRUCT &ps) + EndPaint(HWND hwnd)
在处理WM_PAINT消息时调用BeginPaint,BeginPaint会先擦除无效区域背景同时填充ps的各个字段
调用BeginPaint会使整个用户区域"有效" 但是只在先前的无效区域绘图
可以用InvalidRect手动指定无效区域
当消息队列里没有WM_PAINT消息时 InvalidateRect会显式生成WM_PAINT消息
如果有WM_PAINT消息 Windows会计算出一个新的无效矩形 不再重复置入WM_PAINT消息
一般来说 当出现类似"覆盖" "最小化"时才会出现无效区域 这时候我们不需要调用InvalidRect 此时的无效区域是Windows自行检测的
BeginPaint EndPaint要成对使用


2.GetDC(HWND hwnd) + ReleaseDC(HWND hwnd,HDC hdc)
GetDC返回的设备环境句柄中的"裁剪矩形"是整个用户区 这意味着可以在用户区的任意部分进行绘制而不仅仅在无效矩形中
另一层含义是如果不存在无效矩形也没有关系(更准确来说 无效区域跟GetDC+ReleseDC没关系 是一种指哪儿打哪儿的绘图方式)
要注意的是 GetDC不会将无效区域有效化
这就会导致一个问题


当用户区只要有无效区域时(此时UpdateRegion不为空) Windows就会发送WM_PAINT消息
除非调用BeginPaint+EndPaint或者ValidateRect 否则Windows不会将无效区域有效化 因此将会不停地发送WM_PAINT消息


发送WM_PAINT消息会分两步:
举个栗子:假设A是新弹出的一个对话框 A对话框置于原来的活动对话框B前面 造成对话框B的部分或全部被覆盖
在A对话框没有移开之前 WM_PAINT消息放置在消息队列中
当对话框A移开或关闭后 使对话框B原来被覆盖的地方重新可见 那部分被覆盖的地方就称为无效区域
对话框A移开或关闭后 WM_PAINT消息被发送至窗口过程函数进行处理


GetDC()和ReleaseDC()不能使无效区域有效
因此当程序跳出 WM_PAINT 时 无效区域仍然存在 系统就会不断发送WM_PAINT消息
于是程序不断处理WM_PAINT消息 会造成频繁的闪烁
解决方法是调用ValidateRect函数使整个区域变为"有效"


需要说明的是
WM_PAINT的优先级是最低的
这也就是为什么系统很忙时窗口和桌面往往会出现变白/刷新不了/留拖拽痕迹等现象的原因
只有当一个窗口消息空闲时 系统才会抽空检查一下这个窗口的无效区域是否为非空(即检查UpdateRegion是否非空)


3.GetWindowDC(HWND hwnd)
与GetDC()类似 但返回的是整个窗口的设备环境句柄 因此我们就可以在非用户区绘制了 例如标题栏输出
但是相应的要处理的消息是WM_NCPAINT(非客户区绘制消息)