user-0 提问: 关于WM_PAINT和无效区域

回复:
user: user-1
content: 引用 18 楼 user-2 的回复:[quote=引用 17 楼 六道佩恩 的回复:] 这句话可以理解为用背景色重绘背景吗？其实我说的就是默认的情况。如果自己只绘制了一部分区域，那其他区域是用背景色自动重绘吗？ 是的，但应该说先刷背景色，后在上面绘制其他的东西[/quote] 不一定。 比如：     case WM_ERASEBKGND:         return 1;

user: user-2
content: 引用 12 楼 六道佩恩 的回复:另外问下，erase  background 是指重绘窗口吗？ erase  background是指重绘前擦除背景，怎么重绘窗口是你的事情  WM_PAINT消息处理时坐标本来就是以客户区的左上角为原点的 -> 这里我只是说WM_PAINT消息处理时，一般情况下都是以客户区的左上角为原点，有的是以窗口的左上角为原点，有的是以屏幕的左上角为原点，具体看函数的MSDN说明

user: user-2
content: 引用 17 楼 六道佩恩 的回复:这句话可以理解为用背景色重绘背景吗？其实我说的就是默认的情况。如果自己只绘制了一部分区域，那其他区域是用背景色自动重绘吗？ 是的，但应该说先刷背景色，后在上面绘制其他的东西

user: user-0
content: 引用 15 楼 user-2 的回复:先将画布用背景色擦除背景（覆盖掉原来你画的东西） 这句话可以理解为用背景色重绘背景吗？其实我说的就是默认的情况。如果自己只绘制了一部分区域，那其他区域是用背景色自动重绘吗？

user: user-2
content: 重绘是指 WM_PAINT:    BeginPaint(...);    //这中间就是重绘操作，用背景色擦除背景是BeginPaint(...);的工作    EndPaint(...);    return 0;  如果不想擦除背景，使用  case WM_ERASEBKGND: // return nonzero if it erases the background; otherwise, it should return zero.    return 0;

user: user-2
content: 之前不是说默认用背景色重绘背景吗？ ---> 这个是指 WM_PAINT:    BeginPaint(...);    //这中间没有操作,默认用背景色重绘背景    EndPaint(...);    return 0;  引用 14 楼 六道佩恩 的回复:windows程序设计第五版说的是默认处理WM_PAINT是BeginPaint和EndPaint就没了，这其中按理说有重绘背景吧，可是看来看去除了PAINTSTRUCT结构里的擦除标志就没看到其他的了，所以这个“擦除背景”是不是指用背景色擦除背景，这样既算是擦除，也算是重绘？ 这么说吧，窗口上显示的东西好比是你在画布上画画。 有擦除标志时，就先将画布用背景色擦除背景（覆盖掉原来你画的东西），再在上面作画（相当于在新画布上作画） 无擦除标志时，就直接在原来的画面上接着画（相当于在旧画布上修改） 不知说清楚没有

user: user-0
content: 引用 13 楼 user-2 的回复:[quote=引用 12 楼 六道佩恩 的回复:] 另外问下，erase  background 是指重绘窗口吗？ erase  background是指重绘前擦除背景，怎么重绘窗口是你的事情[/quote] 之前不是说默认用背景色重绘背景吗？ windows程序设计第五版说的是默认处理WM_PAINT是BeginPaint和EndPaint就没了，这其中按理说有重绘背景吧，可是看来看去除了PAINTSTRUCT结构里的擦除标志就没看到其他的了，所以这个“擦除背景”是不是指用背景色擦除背景，这样既算是擦除，也算是重绘？

user: user-0
content: 引用 10 楼 user-2 的回复:WM_PAINT消息处理时坐标本来就是以客户区的左上角为原点的 去测试了下，PAINTSTRUCT包含的矩形的确应该是拷贝的，在绘制前修改区域后仍然全部更新，但InvalidateRect还是应该能说明问题的吧，限制区域后只有部分更新，显示的量和之前一样，说明并不是从无效区域开始显示的。另外问下，erase  background 是指重绘窗口吗？

user: user-0
content: 引用 10 楼 user-2 的回复:WM_PAINT消息处理时坐标本来就是以客户区的左上角为原点的 你确定是处理WM_PAINT才有的？我觉得跟消息没关系吧，HDC是相对于客户区的，无效区域只是在系统绘图时更新的范围，我想验证的就是“hdc为无效区效的"设备环境"”这句话，我觉得这句话应该是错的

user: user-2
content: WM_PAINT消息处理时坐标本来就是以客户区的左上角为原点的

user: user-2
content: 引用 7 楼 六道佩恩 的回复:我试着修改PAINTSTRUCT包含的矩形，左和上由0改为了100，结果绘制的文字仍然在客户区左上角，并没有发生改变 我觉得你修改这个是没有用的（猜测），这个只是接收系统认为的无效区域，是个副本 不过不是很明白你的用意，你想验证啥

user: user-0
content: 引用 5 楼 user-2 的回复:你第一次指定一个坐标来绘制文字时（即响应第一个WN_PAINT消息时），窗口刚创建，整个客户区都是无效的 经测试，坐标应该还是相对客户区的，只有无效区被更新

user: user-1
content: 自绘提高效率用。

user: user-0
content: 引用 5 楼 user-2 的回复:你第一次指定一个坐标来绘制文字时（即响应第一个WN_PAINT消息时），窗口刚创建，整个客户区都是无效的 我试着修改PAINTSTRUCT包含的矩形，左和上由0改为了100，结果绘制的文字仍然在客户区左上角，并没有发生改变

user: user-0
content: 引用 5 楼 user-2 的回复:你第一次指定一个坐标来绘制文字时（即响应第一个WN_PAINT消息时），窗口刚创建，整个客户区都是无效的 这个我知道，我的意思是说，之后的绘图，指定坐标（X,Y）其实就不是相对客户区的了？

user: user-2
content: 你第一次指定一个坐标来绘制文字时（即响应第一个WN_PAINT消息时），窗口刚创建，整个客户区都是无效的

user: user-0
content: 引用 1 楼 赵4老师 的回复:自绘提高效率用。 不会呀。。。

user: user-0
content: 引用 2 楼 user-2 的回复:1. 在Win2000和XP下，窗口被其他窗口覆盖，在其他窗口移开后，被覆盖的窗口确实会收到WM_PAINT消息，这是由于当时内存一般比较少，系统没有保存被覆盖的内容，所以要求程序自己重画，但为了效率，重画的是被覆盖的范围，即PAINTSTRUCT中的无效区域的矩形在这里起作用，WM_PAINT中hdc = BeginPaint(hwnd, &ps); //严格来讲，hdc为无效区效的"设备环境"，在此区域外的作图，都将被忽略，实际上是被裁剪了。 至于其他窗口移开后你没有收到WM_PAINT，我在Win10下也得到了同样的结果，确实没有收到，我猜可能是Win10改变了策略，现在内存一般比较大，系统保存了被覆盖的内容，当其他窗口移开后，系统直接恢复被覆盖的区域，就不要求程序自己重画了。  2. 如果图形不复杂，就不考虑无效区域，直接将整个窗口重绘一遍；如果很复杂，重画的代价很大（比如画什么要根据大量的计算后才能决定），很慢，那么还是只画无效区域。  比如绘制文字时，可以指定一个坐标来绘制，这个坐标是相对于客户区坐标的，可如果说有无效区域时只绘制无效区域，那么岂不是和这个相对于客户区的HDC相矛盾了？HDC由客户区的变成了无效区域的HDC？

user: user-2
content: 引用 楼主 六道佩恩 的回复:1. 测试用其他窗口覆盖本窗口，并没有收到WM_PAINT（只收到创建处的一次，使用了BeginPaint） 2. 我们在绘图时要考虑无效区域吗？好像不用吧？应该都是遇到WM_PAINT就把整个窗口重绘一遍是吧？那这些无效区域的矩形是干嘛的？ 1. 在Win2000和XP下，窗口被其他窗口覆盖，在其他窗口移开后，被覆盖的窗口确实会收到WM_PAINT消息，这是由于当时内存一般比较少，系统没有保存被覆盖的内容，所以要求程序自己重画，但为了效率，重画的是被覆盖的范围，即PAINTSTRUCT中的无效区域的矩形在这里起作用，WM_PAINT中hdc = BeginPaint(hwnd, &ps); //严格来讲，hdc为无效区效的"设备环境"，在此区域外的作图，都将被忽略，实际上是被裁剪了。 至于其他窗口移开后你没有收到WM_PAINT，我在Win10下也得到了同样的结果，确实没有收到，我猜可能是Win10改变了策略，现在内存一般比较大，系统保存了被覆盖的内容，当其他窗口移开后，系统直接恢复被覆盖的区域，就不要求程序自己重画了。  2. 如果图形不复杂，就不考虑无效区域，直接将整个窗口重绘一遍；如果很复杂，重画的代价很大（比如画什么要根据大量的计算后才能决定），很慢，那么还是只画无效区域。