2009-10-30 65 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 
相關問題