我有个应用程序,有多个窗口,可能被自己应用窗口挡住,或者被别的应用程序的窗口挡住即窗口被遮挡.我怎么判定窗口被遮挡.
谢谢

解决方案 »

  1.   

    你可以设定你的窗口为TopMost,但你说的这种要求,恐怕很难做到.
      

  2.   

    设置TopMost应该不行,我是在做窗口吸附功能,象winmap那中效果,几个窗口吸附在一起,主要是点击其中一个窗口,另外的窗口如果被别的窗口挡住了,就要把窗口提前,基本上就是这个概念.
      

  3.   

    不知道有没有这种API函数来判断,那对API熟悉点的.
    不胜感激.
      

  4.   

    用FindWindow或FindWindowEx找到此窗口的句柄,然后用GetWindowPlacement返回指定窗口的显示状态以及被恢复的、最大化的和最小化的窗口位置
    在根据GetWindowPlacement取得的信息判断。
    具体用法自己找吧
      

  5.   

    按照你的描述,在form的Activated事件中写代码就可以了。public event EventHandler Activated
    当使用代码激活或用户激活窗体时发生。
      

  6.   

    谢谢各位,刚才走开了.caofusheng 
    草上飞 
    等 级:
     发表于:2008-01-20 15:10:596楼 得分:0 
    用FindWindow或FindWindowEx找到此窗口的句柄,然后用GetWindowPlacement返回指定窗口的显示状态以及被恢复的、最大化的和最小化的窗口位置 
    在根据GetWindowPlacement取得的信息判断。 
    具体用法自己找吧 
     
    =============
    我试下,GetWindowPlacement这个方法不值得那个属性能判断出是否被挡住
       ouhou 按照你的描述,在form的Activated事件中写代码就可以了。 public   event   EventHandler   Activated 
    当使用代码激活或用户激活窗体时发生。 
     =====
    事件那部分代码都搞定了,就是还没完成断出是否被挡住,如果挡住激活下.
    现在我没判断,都去激或下,窗口闪动太多了
      

  7.   

    VirtualAS 虚拟艾非 
    看窗口有没有焦点 
    ==========================
    看焦点没用的,窗口没挡住,也有可能失去焦点
     
    请教下`GetWindowPlacement涵数返回的WINDOWPLACEMENT具体参数说明能详细说明下吗?
      

  8.   

    GetWindowPlacement涵数返回的WINDOWPLACEMENT
    我全部跟踪了下,发现只能取得它的大小,或者最大话,最小话,另外没什么发现.
    各位高手再帮忙看看啊,我以前做b/s比较多,winform编程不太搞,很多不熟悉.
      

  9.   

    Optione 
    昵称非法 
    等 级:
     发表于:2008-01-21 00:42:5812楼 得分:0 
    尝试:GetForegroundWindow 
     
    ===========================
    应该不行,这个函数只能获取活动窗口,屏幕上能挡住别的窗口的窗口一般都不是激活窗口。
    我也试过gettopwindow只能取得最顶层的窗口。都不能判断出窗口是否被挡住。
    各位高手还有别的方法能判断下吗?取巧的方法也行。
      

  10.   

    定时刷新,将窗口为TopMost,也就是说,你失去焦点将会自动获得焦点~~~
      

  11.   

    重写OnPaint(),如果失去焦点的时候重绘就肯定是被遮盖了.然后获取当前具有焦点的窗体就行了
      

  12.   

    uscool 
    小小风 
    等 级:
     发表于:2008-01-21 09:20:2916楼 得分:0 
    定时刷新,将窗口为TopMost,也就是说,你失去焦点将会自动获得焦点~~~ 
     
    =============================================
    这个不现实,我程序里的所有窗口都有可能吸附在一起,把所有窗口设置TopMost等于没设置。
      

  13.   

    你可以在你程序的主窗体上加个菜单项,比如:mnuWindows(窗口),把这个菜单的MdiList属性设为True,每次打开一个子窗体,该菜单项会增加这个窗体标题的子菜单项,通过子菜单项的Checked属性来判断当前激活的子窗体和非激活的子窗体了
    下面这段代码是VB.Net的,你可以参考一下
       
    For Each mnu As MenuItem In mnuWindows.MenuItems
                If mnu.Checked Then
                    MessageBox.Show(mnu.Text & "窗口是激活状态!")
                Else
                    MessageBox.Show(mnu.Text & "窗口是非激活状态!")
                End If
            Next
      

  14.   

    如果你不想让用户看到这个mnuWindows(窗口)菜单,你可以隐藏它,只在你判断代码里用到它就可以了
      

  15.   

    这个问题我以前也问过,想到的办法就是Invalidate刷新一下,看看Paint事件是否触发或者刷新区域无效。
    缺点就是不能判断窗体标题栏是否也被遮挡。
    参考如下代码:
    bool windowPaint = false;private void Form1_Paint(object sender, PaintEventArgs e)
    {
        windowPaint = e.ClipRectangle.Width > 0 && e.ClipRectangle.Height > 0; // 存在刷新的区域
    }
    private void timer1_Tick(object sender, EventArgs e)
    {
        windowPaint = false;
        Invalidate();
        if (windowPaint)
            Text = "客户区可见";
        else Text = "客户区不可见";
    }
      

  16.   

    一个更好的解决方案,不用加事件,也可以判断标题;
    没有考虑不规则窗体的情况。
    参考如下代码:
    using System.Runtime.InteropServices;[DllImport("user32.dll")]
    public static extern bool IsWindowVisible(IntPtr hWnd);[DllImport("user32.dll")]
    public static extern IntPtr GetWindowDC(IntPtr hWnd);[DllImport("user32.dll")]
    public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);[DllImport("gdi32.dll")]
    public static extern int GetClipBox(IntPtr hDC, ref Rectangle lpRect);/// <summary>
    /// 判断窗体是否被遮挡
    /// </summary>
    /// <param name="hWnd">窗体句柄</param>
    /// <returns>返回窗体是否被完全遮挡</returns>
    public bool WindowPall(IntPtr AHandle)
    {
        if (!IsWindowVisible(AHandle)) return false; // 窗体不可见
        IntPtr vDC = GetWindowDC(AHandle);
        try
        {
            Rectangle vRect = new Rectangle();
            GetClipBox(vDC, ref vRect);
            return vRect.Width - vRect.Left <= 0 && vRect.Height - vRect.Top <= 0;
            // 特别说明:Rectangle.Width对应API中RECT.Right、Rectangle.Height为RECT.Bottom
        }
        finally
        {
            ReleaseDC(AHandle, vDC);
        }
    }private void timer1_Tick(object sender, EventArgs e)
    {
        Text = WindowPall(Handle).ToString();
    }
      

  17.   

    api Getwindowrect  获取 窗口 X Y 高宽长度.. 是否少与 其他窗口的 X Y 高宽长度 可以吗? 我也不太懂..只是感觉当你打开你的 窗口 Getwindowrect 信息保存起来.. 然后 当你打开其他窗口的时候 用那窗口的信息  对比你应用程序的窗口信息.. 
      我的愚见.. 有空帮我顶下贴.. 我也有个大困难 http://topic.csdn.net/u/20080119/13/fc2a2576-e924-4cf0-a185-e67853afab91.htmlhttp://topic.csdn.net/u/20080119/11/0d1b8aec-b349-4699-b837-fdeac8ab22a8.html
      

  18.   

    1. 取出当前活动窗体
    2. 用GetClientRect获取各个窗体在屏幕上的位置.
    3. 检查是否有重合
    4. 如果有重合, 取得重合部分中心点, 用GetWindowFromPoint, 获取重合点的top窗体, 检查是否是你的窗体, 如果不是, 说明被遮挡.
      

  19.   

    private void Form1_Paint(object sender, PaintEventArgs e)
    ...{
        Text = e.ClipRectangle.Width.ToString();
    }
    在窗体的Paint事件中,有一个ClipRectangle的属性,解释为“获取要在其中进行绘画的矩形”
    这个属性的作用就是:窗体在刷新的时候,为提高效率一些被遮挡的区域就不用再绘制。
    那么判断窗体是否被完全遮挡,只需要判断刷新时是否产生有效绘制。
    bool windowPaint = false;private void Form1_Paint(object sender, PaintEventArgs e)
    ...{
        windowPaint = e.ClipRectangle.Width > 0 && e.ClipRectangle.Height > 0; // 存在刷新的区域
    }private void timer1_Tick(object sender, EventArgs e)
    ...{
        windowPaint = false;
        Invalidate();
        if (windowPaint)
            Text = "客户区可见";
        else Text = "客户区不可见";
    }根据这个思路写出如上代码。测试的结果是对客户区判断有效,对标题栏判断失效。
    联想到Delphi中OnPaint中没有参数,这个刷新区域能通过Canvas.ClipRect属性获得。
    分析VCL源代码
    function TCanvas.GetClipRect: TRect;
    begin
      RequiredState([csHandleValid]);
      GetClipBox(FHandle, Result);
    end;
    找到GetClipBox函数。
    按经验GetWindowDC可以取得整个窗体的画布(包括客户区和非客户区);
    这样就有了线索,二话不说动手测试吧。
    ---Delphi----
    function WindowPall(AHandle: THandle): Boolean; // 窗体是否被遮住
    var
      vDC: THandle;
      vRect: TRect;
    begin
      Result := False;
      if not IsWindowVisible(AHandle) then Exit;
      vDC := GetWindowDC(AHandle);
      try
        GetClipBox(vDC, vRect);
        Result := (vRect.Right - vRect.Left <= 0) and (vRect.Bottom - vRect.Top <= 0);
      finally
        ReleaseDC(AHandle, vDC);
      end;
    end; { WindowPall }procedure TForm1.Timer1Timer(Sender: TObject);
    begin
      Application.Title := BoolToStr(WindowPall(Handle), True);
    end;
    达到理想效果。翻译成C#。
     
    using System.Runtime.InteropServices;[DllImport("user32.dll")]
    public static extern bool IsWindowVisible(IntPtr hWnd);[DllImport("user32.dll")]
    public static extern IntPtr GetWindowDC(IntPtr hWnd);[DllImport("user32.dll")]
    public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);[DllImport("gdi32.dll")]
    public static extern int GetClipBox(IntPtr hDC, ref Rectangle lpRect);/**//// <summary>
    /// 判断窗体是否被遮挡
    /// </summary>
    /// <param name="hWnd">窗体句柄</param>
    /// <returns>返回窗体是否被完全遮挡</returns>
    public bool WindowPall(IntPtr AHandle)
    ...{
        if (!IsWindowVisible(AHandle)) return false; // 窗体不可见
        IntPtr vDC = GetWindowDC(AHandle);
        try
        ...{
            Rectangle vRect = new Rectangle();
            GetClipBox(vDC, ref vRect);
            return vRect.Width - vRect.Left <= 0 && vRect.Height - vRect.Top <= 0;
            // 特别说明:Rectangle.Width对应API中RECT.Right、Rectangle.Height为RECT.Bottom
        }
        finally
        ...{
            ReleaseDC(AHandle, vDC);
        }
    }private void timer1_Tick(object sender, EventArgs e)
    ...{
        Text = WindowPall(Handle).ToString();
    }这个解决方案没有考虑不规则窗体的情况,可能和GetClipRgn有关,有兴趣的朋友可以自己做做,做出来别忘记和大家分享一下。主页上的某文章下次提问先找找多好哎 orz,服了楼主
      

  20.   

    谢谢各位
    to zswang
    你的方法可以判断全部遮挡,但是不能判断,部分遮挡。不过还是谢谢。to shrinerain 
    你的方法还没试,等晚上慢慢搞。谢谢各位还有好的方法吗?不胜感激。
     
      

  21.   

    个人认为 Form.ContainsFocus;就搞定了,楼上的牛人们意下如何?