2009-10-30 73 views
9

通常你使用Form.Visible来检查Window是否可见。但有时在屏幕窗口下面是其他窗口,所以它真的是看不见的。如何检查窗口在Windows窗体中是否真的可见?

那么如果窗口真的可见或不可见,如何检查C#窗体?

我想做到这一点:当我点击我的键盘上的CTRL + K,并且我的窗口在我的屏幕上可见时,它什么也不做。但是当它位于其他窗口的下方时,它会弹出(位于前面)。

亲切的问候

回答

1

嗯......奇怪的问题。 :P

也许你可以问的形式位置,如果两种形式interlap(搞清楚自己COORDS,并进行了简单的方法)检查​​,如果一个表格具有焦点()。如果它具有焦点,那么其他必须是“不可见的”(,因为用户不能看到它,因为它在其他形式之下)。

很显然,这种方法很冒险至多,但它是你可以开始使用的东西。

2

要回答这个问题,您可以尝试调用WindowFromPoint API函数在窗体上的不同位置查找窗口,并检查它是否返回您期望的那个句柄。

+0

这是我在淘宝网和SO之后的最佳答案。 SLaks救援!这个信誉本身就说明了一切。 – 2016-08-10 20:22:35

4

您可以使用Windows API枚举所有窗口,检索它们的Z顺序并将其与窗口的Z顺序进行比较。我认为有人已经这样做了here

0

您应该能够通过重写OnPaint方法来了解您的窗口是否可见。您需要将控制权传递给基类以完成实际绘制,但是您将能够检测是否收到绘制消息。 更新:不,这不起作用,对不起!

原则上,Activate方法应该使您的窗口前台,但实际上,如果其他进程有输入焦点,我总是发现这个问题。如果你真的希望有人看到一个窗口,设置最高位,但期望他们恼火!如果你能摆脱这种情况,关闭窗户并重新打开窗户的一个绝对方法就是关闭窗户。

实现目标的一种方法是使用通知图标,这将以符合Windows UI准则的方式引起用户的注意。

6

我使用谷歌搜索,但coudn't找到任何直接的答案,看看窗口的一部分是否真正可见的用户。如果鼠标当前位于窗口可见部分的顶部,我实际上需要一种“击中”窗体的方法。我想我会分享需要几天时间完成的代码:

public class VisibilityTester 
{ 
    private delegate bool CallBackPtr(int hwnd, int lParam); 
    private static CallBackPtr callBackPtr; 

    /// <summary> 
    /// The enumerated pointers of actually visible windows 
    /// </summary> 
    public static List<IntPtr> enumedwindowPtrs = new List<IntPtr>(); 
    /// <summary> 
    /// The enumerated rectangles of actually visible windows 
    /// </summary> 
    public static List<Rectangle> enumedwindowRects = new List<Rectangle>(); 

    /// <summary> 
    /// Does a hit test for specified control (is point of control visible to user) 
    /// </summary> 
    /// <param name="ctrlRect">the rectangle (usually Bounds) of the control</param> 
    /// <param name="ctrlHandle">the handle for the control</param> 
    /// <param name="p">the point to test (usually MousePosition)</param> 
    /// <param name="ExcludeWindow">a control or window to exclude from hit test (means point is visible through this window)</param> 
    /// <returns>boolean value indicating if p is visible for ctrlRect</returns> 
    public static bool HitTest(Rectangle ctrlRect, IntPtr ctrlHandle, Point p, IntPtr ExcludeWindow) 
    { 
     // clear results 
     enumedwindowPtrs.Clear(); 
     enumedwindowRects.Clear(); 

     // Create callback and start enumeration 
     callBackPtr = new CallBackPtr(EnumCallBack); 
     EnumDesktopWindows(IntPtr.Zero, callBackPtr, 0); 

     // Go from last to first window, and substract them from the ctrlRect area 
     Region r = new Region(ctrlRect); 

     bool StartClipping = false; 
     for (int i = enumedwindowRects.Count - 1; i >= 0; i--) 
     { 
      if (StartClipping && enumedwindowPtrs[i] != ExcludeWindow) 
      { 
       r.Exclude(enumedwindowRects[i]); 
      } 

      if (enumedwindowPtrs[i] == ctrlHandle) StartClipping = true; 
     } 

     // return boolean indicating if point is visible to clipped (truly visible) window 
     return r.IsVisible(p); 
    } 

    /// <summary> 
    /// Window enumeration callback 
    /// </summary> 
    private static bool EnumCallBack(int hwnd, int lParam) 
    { 
     // If window is visible and not minimized (isiconic) 
     if (IsWindow((IntPtr)hwnd) && IsWindowVisible((IntPtr)hwnd) && !IsIconic((IntPtr)hwnd)) 
     { 
      // add the handle and windowrect to "found windows" collection 
      enumedwindowPtrs.Add((IntPtr)hwnd); 

      RECT rct; 

      if (GetWindowRect((IntPtr)hwnd, out rct)) 
      { 
       // add rect to list 
       enumedwindowRects.Add(new Rectangle(rct.Left, rct.Top, rct.Right - rct.Left, rct.Bottom - rct.Top)); 
      } 
      else 
      { 
       // invalid, make empty rectangle 
       enumedwindowRects.Add(new Rectangle(0, 0, 0, 0)); 
      } 
     } 

     return true; 
    } 


    [DllImport("user32.dll")] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    static extern bool IsWindowVisible(IntPtr hWnd); 

    [DllImport("user32.dll")] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    static extern bool IsWindow(IntPtr hWnd); 

    [DllImport("user32.dll")] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    static extern bool IsIconic(IntPtr hWnd); 

    [DllImport("user32.dll")] 
    private static extern int EnumDesktopWindows(IntPtr hDesktop, CallBackPtr callPtr, int lPar); 

    [DllImport("user32.dll")] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect); 

    [StructLayout(LayoutKind.Sequential)] 
    private struct RECT 
    { 
     public int Left;  // x position of upper-left corner 
     public int Top;   // y position of upper-left corner 
     public int Right;  // x position of lower-right corner 
     public int Bottom;  // y position of lower-right corner 

     public override string ToString() 
     { 
      return Left + "," + Top + "," + Right + "," + Bottom; 
     } 
    } 
} 
1

你也可以..:)从窗口对应的AutomationElement中获取ClickablePoint属性。 我不是100%确定这是否完全准确,尽管..它在99%的案例中对我有效,我仍在检查其他1%,问题在哪里(可能在我身边或不好用户处理,或。)

-3

只需将Form.AlwaysOnTop属性设置为true

+0

如果另一个窗口也具有相同的属性,将无济于事 – Jules 2013-03-27 21:01:10

1

我aktually试图执行SLaks建议。虽然我在VB.NET中编写它,但不是C#

Friend Structure PointStruct 
    Public x As Int32 
    Public y As Int32 
End Structure 

<System.Runtime.InteropServices.DllImport("user32.dll")> _ 
Friend Function WindowFromPoint(ByVal Point As PointStruct) As IntPtr 
End Function 

''' <summary> 
''' Checks if a control is actually visible to the user completely 
''' </summary> 
''' <param name="control">The control to check.</param> 
''' <returns>True, if the control is completely visible, false else.</returns> 
''' <remarks>This is not 100% accurate, but feasible enough for my purpose.</remarks> 
Public Function IsControlVisibleToUser(ByVal control As Windows.Forms.Control) As Boolean 
    If Not control.Visible Then Return False 

    Dim bAllPointsVisible As Boolean = True 
    Dim lPointsToCheck As New List(Of Point) 
    'Add the points to check. In this case add the edges and some border points 
    'between the edges. 
    'Strangely, the exact edge points always return the false handle. 
    'So we add a pixel into the control. 
    lPointsToCheck.Add(New Point(control.Left + 1, control.Top + 1)) 
    lPointsToCheck.Add(New Point(control.Right - 1, control.Top + 1)) 
    lPointsToCheck.Add(New Point(control.Right - 1, control.Bottom - 1)) 
    lPointsToCheck.Add(New Point(control.Left + 1, control.Bottom - 1)) 
    lPointsToCheck.Add(New Point(control.Left + control.Width/2, control.Top + 1)) 
    lPointsToCheck.Add(New Point(control.Right - 1, control.Top + control.Height/2)) 
    lPointsToCheck.Add(New Point(control.Right - control.Width/2, control.Bottom - 1)) 
    lPointsToCheck.Add(New Point(control.Left + 1, control.Bottom - control.Height/2)) 
    'lPointsToCheck.Add(New Point(control.Left + control.Width/2, control.Top + control.Height/2)) 

    'Check each point. If all points return the handle of the control, 
    'the control should be visible to the user. 
    For Each oPoint In lPointsToCheck 
     Dim sPoint As New PointStruct() With { 
      .x = oPoint.X, _ 
      .y = oPoint.Y _ 
     } 
     bAllPointsVisible = bAllPointsVisible And (_ 
      (WindowFromPoint(sPoint) = control.Handle) _ 
     ) 
    Next 

    Return bAllPointsVisible 
End Function 
相关问题