通常情况下,你使用Form.Visible检查窗口是可见。 但有时在屏幕窗口上低于其他窗口,以便它真的看不见。
因此,如何在C#Windows窗体检查,如果窗口是真的可见或不可见?
我想做到这一点:当我点击我的键盘上的CTRL + K和我的窗口可见我的屏幕上它什么都不做。 但是,当它它弹出顶端其他窗口的下方(移到前面)。
亲切的问候
通常情况下,你使用Form.Visible检查窗口是可见。 但有时在屏幕窗口上低于其他窗口,以便它真的看不见。
因此,如何在C#Windows窗体检查,如果窗口是真的可见或不可见?
我想做到这一点:当我点击我的键盘上的CTRL + K和我的窗口可见我的屏幕上它什么都不做。 但是,当它它弹出顶端其他窗口的下方(移到前面)。
亲切的问候
您可以拨打Activate
窗体上的方法,将其带到前方,如果它是不是已经。
但是,请注意,如果不同的程序被激活时,它通常会简单地刷新桌面按键(取决于你来自哪里,称呼它)。 这是Windows的对焦点盗窃的防护标准 ,你不应该试图解决它 。
我GOOGLE了低谷网页,但coudn't找到任何直接的答案,看是否有窗口的一部分是用户真正可见。 其实,我需要一种方法来“则hitTest”的形式,如果鼠标目前在窗口的可见部分的顶部。 我想我会分享历时数天才能完成的代码:
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;
}
}
}
你可以使用Windows API来枚举所有窗口,检索其Z顺序,并将其与窗口的Z顺序进行比较。 我觉得有人这样做已经在这里 。
要回答这个问题的问,你可以尝试调用WindowFromPoint
API函数查找的不同点,窗口的形式,并检查其是否返回任何你想到会在这一点上的手柄。
嗯......奇怪的问题。 :P
也许你会问的形式位置,如果两种形式interlap(搞清楚自己COORDS,并进行了简单的方法)检查,如果一个表格具有焦点()。 如果它具有焦点,那么其他必须是“隐形”( 在这个意义上,用户看不到它,因为它是另一种形式的下面 )。
显然,这种方法哈克在最好的 ,但它的东西,你就可以开始一起工作。
你也可以.. :)您可以通过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
你应该能够了解您的窗口是通过重写OnPaint方法可见。 你要控制传递给基类,以便做实际的绘制,但你可以检测是否接收到绘制消息。 更新:不,这是不行的,对不起!
原则上,激活方法应该把你的窗口到前台,但在实践中我总是发现这个问题,如果其他进程具有输入焦点。 如果你真的希望有人看到一个窗口,设置最高位,但预计它们是恼火! 一个正确的方式得到一些关注的窗口是关闭并重新打开它,如果你能得逞的。
实现你要寻找的一种方法是使用一个通知图标,这将让用户的注意力的方式,符合Windows用户界面的指导方针。
只需将设置Form.AlwaysOnTop
属性为true
。