ywsswy / blog

blog is not bug.
0 stars 0 forks source link

客户区绘制、VM_PAINT等问题 #1

Open ywsswy opened 5 years ago

ywsswy commented 5 years ago

demo写了 Game_Paint1 和 Game_Paint2,当按‘2’键时绘制图2,当按其他键时绘制图1。 先看可能出现的三种现象: 1)按了键'2',显示立即从图1变成图1,这是我们希望的理想情况。 2)按了键'2',并没有立刻显示图2,而是当“客户区出现遮掩后重见天日”(后面简称为重见天日)时,才会看到图1变成了图2。 第二种现象代码如下:(重见天日时,VM_PAINT触发一次,才能看到按键切换绘图的效果)

WndProc(){
    /* .... */
    case WM_PAINT:
        YGlobalVars::log1.w(__FILE__, __LINE__, YLog::INFO, "WM_PAINT","");
        if(YGlobalVars::lastkey == 0x32){
            Game_Paint2(hwnd);
        }else{
            Game_Paint1( hwnd);
        }
        ValidateRect(hwnd, NULL);
        break;
    default:
        return DefWindowProc( hwnd, message, wParam, lParam );
    }
    return 0;
}
VOID Game_Paint1(HWND hwnd){
    YGlobalVars::log1.w(__FILE__, __LINE__, YLog::INFO, "Game_Paint1 start","");
    SelectObject(YGlobalVars::hMdc,YGlobalVars::hBitmap1);  
    BitBlt(YGlobalVars::hdc,0,0,YGlobalVars::window_width,YGlobalVars::window_height,YGlobalVars::hMdc,0,0,SRCCOPY);
    return;
}
VOID Game_Paint2(HWND hwnd){
    YGlobalVars::log1.w(__FILE__, __LINE__, YLog::INFO, "Game_Paint2 start","");
    SelectObject(YGlobalVars::hMdc,YGlobalVars::hBitmap2);  
    BitBlt(YGlobalVars::hdc,0,0,YGlobalVars::window_width,YGlobalVars::window_height,YGlobalVars::hMdc,0,0,SRCCOPY);
    return;
}
WinMain(){
    /* ... */
    while( msg.message != WM_QUIT ){
        if( PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) ){
            DispatchMessage( &msg );
        }
    }
    /* ... */
}

如果把第二种现象的代码中 ValidateRect(hwnd, NULL); 去掉,就会出现第一种现象。(VM_PAINT不停得触发。这说明:如果不调用这个 ValidateRect,VM_PAINT消息将一直存在于消息队列中,时刻绘制) 紧接着,如果把 ValidateRect(hwnd, NULL); 下面的 break; 去掉,又会出现第二种现象。(重见天日时,VM_PAINT触发一次,才能看到按键切换绘图的效果。这说明不 break 时,进入default 处理的 DefWindowProc 系统函数中包含了类似 ValidateRect 的功能,可以把VM_PAINT消息从队列中移除)

3)但是这里还有第三种现象,把 Game_Paint2(hwnd); 去掉,这样当“客户区出现遮掩后重见天日”(后面简称为重见天日)时,“重见天日”的部分变成白色,这是一种类似橡皮擦的现象。 (未完,待续。。。)(卒) 重见天日时,不仅仅有VM_PAINT,还会有其他绘图有关的消息。

客户区是指整个应用程序窗口中没有被标题栏、边框、菜单栏、工具栏、状态栏和滚动条占用的区域。 这里有两个概念:有效区和无效区,其中需要重新绘制的部分被称作无效区,如果客户区有了无效区域,结果就是windows会往消息队列中发出一条WM_PAINT消息。 如果窗口处理过程在处理一条WM_PAINT消息之前,客户区的另外一部分也失效了,windows会计算出覆盖这两块区域的一个新的矩形,并且更新绘制信息结构中的数据,而不会在消息队列中放置另一个WM_PAINT消息。 InvalidateRect函数强制使windows发出一条WM_PAINT消息。 ValidateRect则相反,如果调用了ValidateRect函数后,整个客户区都有效了,消息队列中的WM_PAINT消息就会被删除;如果不调用这个ValidateRect,VM_PAINT消息将一直存在,时刻绘制