通常你使用Form.Visible來檢查Window是否可見。但有時在屏幕窗口下面是其他窗口,所以它真的是看不見的。如何檢查窗口在Windows窗體中是否真的可見?
那麼如果窗口真的可見或不可見,如何檢查C#窗體?
我想做到這一點:當我點擊我的鍵盤上的CTRL + K,並且我的窗口在我的屏幕上可見時,它什麼也不做。但是當它位於其他窗口的下方時,它會彈出(位於前面)。
親切的問候
通常你使用Form.Visible來檢查Window是否可見。但有時在屏幕窗口下面是其他窗口,所以它真的是看不見的。如何檢查窗口在Windows窗體中是否真的可見?
那麼如果窗口真的可見或不可見,如何檢查C#窗體?
我想做到這一點:當我點擊我的鍵盤上的CTRL + K,並且我的窗口在我的屏幕上可見時,它什麼也不做。但是當它位於其他窗口的下方時,它會彈出(位於前面)。
親切的問候
您可以調用表單上的Activate
方法,如果它尚未出現,請將其置於前面。
但是,請注意,如果一個不同的程序處於活動狀態,它通常會簡單地閃爍桌面按鈕(取決於您從哪裏調用它)。這是Windows'standard protection against focus-stealing和你should not try to work around it。
嗯......奇怪的問題。 :P
也許你可以問的形式位置,如果兩種形式interlap(搞清楚自己COORDS,並進行了簡單的方法)檢查,如果一個表格具有焦點()。如果它具有焦點,那麼其他必須是「不可見的」(,因爲用戶不能看到它,因爲它在其他形式之下)。
很顯然,這種方法很冒險至多,但它是你可以開始使用的東西。
要回答這個問題,您可以嘗試調用WindowFromPoint
API函數在窗體上的不同位置查找窗口,並檢查它是否返回您期望的那個句柄。
您可以使用Windows API枚舉所有窗口,檢索它們的Z順序並將其與窗口的Z順序進行比較。我認爲有人已經這樣做了here。
您應該能夠通過重寫OnPaint方法來了解您的窗口是否可見。您需要將控制權傳遞給基類以完成實際繪製,但是您將能夠檢測是否收到繪製消息。 更新:不,這不起作用,對不起!
原則上,Activate方法應該使您的窗口前臺,但實際上,如果其他進程有輸入焦點,我總是發現這個問題。如果你真的希望有人看到一個窗口,設置最高位,但期望他們惱火!如果你能擺脫這種情況,關閉窗戶並重新打開窗戶的一個絕對方法就是關閉窗戶。
實現目標的一種方法是使用通知圖標,這將以符合Windows UI準則的方式引起用戶的注意。
我使用谷歌搜索,但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;
}
}
}
你也可以..:)從窗口對應的AutomationElement中獲取ClickablePoint屬性。 我不是100%確定這是否完全準確,儘管..它在99%的案例中對我有效,我仍在檢查其他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
這是我在淘寶網和SO之後的最佳答案。 SLaks救援!這個信譽本身就說明了一切。 – 2016-08-10 20:22:35