我的考虑是只有Z-order在指定窗口之前的窗口才可能造成遮挡,又由于子窗口不会显示超出顶级窗口(top-level)的范围,所以只要检查Z-order在指定窗口之前的可见顶级窗口是否造成遮挡就行了。另一方面,指定窗口可能是顶级窗口或者子窗口。1、如果是顶级窗口就检查在它之前的顶级窗口;2、如果是子窗口还需要检查在它之前的子兄弟窗口是否遮挡,然后向上检查父窗口的兄弟窗口(父窗口不用检查),如此迭代直到顶级窗口为止,之后和情况1一样。还有我理解是顶级窗口和子窗口的区别在于顶级窗口没有WS_CHILD(WS_CHILDWINDOW等同)风格测试了一下似乎没什么问题,但只检查窗口矩形(Rect)是否被遮挡,没有进一步用区域(RGN)做细致比较,也没有考虑透明窗口代码如下,请大家看看有什么问题没有:bool IsCoveredByOtherWindow(HWND hWnd)
{
    RECT rcTarget;
    GetWindowRect(hWnd, &rcTarget);    bool isChild = (WS_CHILD == (GetWindowLong(hWnd, GWL_STYLE) & WS_CHILD));    do 
    {
        HWND hCurWnd = hWnd;        while ( NULL != (hWnd = GetNextWindow(hWnd, GW_HWNDPREV) ) )
        {
            if ( IsWindowVisible(hWnd) )
            {
                RECT rcWnd;
                GetWindowRect(hWnd, &rcWnd);                if ( !((rcWnd.right < rcTarget.left) || (rcWnd.left > rcTarget.right) || 
                    (rcWnd.bottom < rcTarget.top) || (rcWnd.top > rcTarget.bottom)) )
                {
                    return true;
                }
            }
        }        if ( isChild )
        {
            hWnd = GetParent(hCurWnd);
            isChild = hWnd ? (WS_CHILD == (GetWindowLong(hWnd, GWL_STYLE) & WS_CHILD)) : false;
        }
        else
        {
            break;
        }    }while ( true );    return false;
}

解决方案 »

  1.   


    好像可以通过FOCUS来判断是否焦点在当前窗体.
      

  2.   

    刚才发现了一个小问题,对于特例桌面窗口(Desktop)没有专门处理,桌面不在Z-order里面,而且总是位于所有窗口的最底下。原来的代码不改,加两行就可以了。
    bool IsCoveredByOtherWindow(HWND hWnd) 

        RECT rcTarget; 
        GetWindowRect(hWnd, &rcTarget);     bool isChild = (WS_CHILD == (GetWindowLong(hWnd, GWL_STYLE) & WS_CHILD)); 
      
        if ( GetDesktopWindow() == hWnd )                        <- 添加的代码
            hWnd = GetWindow(GetTopWindow(hWnd), GW_HWNDLAST);    <-

        do 
        { 
            HWND hCurWnd = hWnd;         while ( NULL != (hWnd = GetNextWindow(hWnd, GW_HWNDPREV) ) ) 
            { 
                if ( IsWindowVisible(hWnd) ) 
                { 
                    RECT rcWnd; 
                    GetWindowRect(hWnd, &rcWnd);                 if ( !((rcWnd.right < rcTarget.left) || (rcWnd.left > rcTarget.right) || 
                        (rcWnd.bottom < rcTarget.top) || (rcWnd.top > rcTarget.bottom)) ) 
                    { 
                        return true; 
                    } 
                } 
            }         if ( isChild ) 
            { 
                hWnd = GetParent(hCurWnd); 
                isChild = hWnd ? (WS_CHILD == (GetWindowLong(hWnd, GWL_STYLE) & WS_CHILD)) : false; 
            } 
            else 
            { 
                break; 
            }     }while ( true );     return false; 
    }
      

  3.   

    呃。。本来想加红色醒目点的Orz
      

  4.   

    为什么子窗口不会显示超出顶级窗口(top-level)的范围
      

  5.   

    在Init里加一段
    SetWindowPos(NULL, 99, -30, 0, 0, SWP_NOSIZE);
    仍然判断没有遮挡,
    估计是以为只有拖动标题栏才能移动窗口吧,
      

  6.   

    子窗口超出父窗口的部分会被剪裁掉这涉及“被遮挡”的定义了,我这里设定被其他窗口覆盖,但不包括被父窗口剪裁。你的场景应该是“IsWindowCompletelyVisible”,考虑了一下,这种场景确实更多见一下。稍加修改即可。具体怎么测试的?我试了下没发现问题啊。
    我以为判断遮挡有如下几种情况:区域(Region,包括了一般的矩形窗口)、分层窗口(Layered Window)、用绘制下层窗口的方式模拟透明效果,另外还可能需要考虑消息穿透和直接绘屏(桌面上画或者DirectX)。
    遮挡到底是仅仅视觉可见,还是可见可输入,还是通过透明窗口可见但不能获得输入,或者通过透明窗口可见而且可以获得输入,透明度阀值是多少,这要根据应用场景来定义了。有部分是不能简单判断出的,比如模拟透明,还有直接绘屏(如果你的窗口背景色和后面播放器的底色一样,那你的程序就可以放电影了-_-b)。这段代码还有个bug,刚才发现的。对于子窗口的检查有两种特殊情况,就是Z-order排在上面却不挡住下面的窗口,比如分组框(GroupBox),代码里当子窗口看到有个上铺的兄弟GroupBox罩着他,就以为别人看不到自己了,回头跟我们说:“not covered!”另一种是下面挡住上面,比如两个按钮重叠在一起,你会发现Z-order在上面的按钮反而被遮挡了,但是点击重叠区点到的确实是上面的按钮!这是系统绘制子窗口顺序的问题,当上面的窗口指定WS_EX_TRANSPARENT风格时它被最后绘制,不会被挡到,但是如果再加一个WS_EX_TRANSPARENT风格的窗口重叠呢?改改用到MDI判断视图是否完全可见还是可以的,否则处理太麻烦了。能力有限,只能期待高人指教了哇
      

  7.   

    改正:“not covered!”应为“covered!” ^-^b