如何检查我的窗口是不是隐藏/可见?

Posted

技术标签:

【中文标题】如何检查我的窗口是不是隐藏/可见?【英文标题】:How to check if my window gets hidden/visible?如何检查我的窗口是否隐藏/可见? 【发布时间】:2011-06-07 15:24:34 【问题描述】:

如果我在 Windows7 中按下“显示桌面”按钮,我的程序仍然会认为它没有被最小化,如果我在我的程序聚焦时按下WIN+D,那么我的程序才会捕捉到这个最小化命令。如何检查 100% 确定我的程序是否可见?

这是我的主循环:

while(!done)
    if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        if(msg.message == WM_QUIT)
            done = TRUE;
        else
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        
    else if(active)
        render();
    

Edit3:这样好吗?看起来像它的工作:

case WM_WINDOWPOSCHANGED:

        flags = ((PWINDOWPOS)lParam)->flags;
        if((flags & 0x8000) && (flags & SWP_NOCOPYBITS) && (flags & SWP_FRAMECHANGED))
            active = !(flags & SWP_NOACTIVATE);
        
        if((flags & 0x1000) && (flags & 0x0800) && (flags & SWP_NOMOVE) && (flags & SWP_NOSIZE))
            active = 1;
        

case WM_ACTIVATE:

    active = !HIWORD(wParam);
    return 0;

【问题讨论】:

隐藏窗口时会擦除什么? @Cody Gray,我不明白你的意思......你能详细说明一下吗? @Cody,问题是如果我按下“显示桌面”按钮,我的程序渲染循环将继续运行......因为它没有告诉我它被隐藏了。 @Cody,我使用 openGL 进行渲染,我不明白这与我的问题有什么关系。我故意放了winapi标签:这应该与窗口消息处理有关。我怀疑我的程序与其他程序有什么不同,因为很多人就像我一样只是复制粘贴 nehe 教程。所以……请理解。 如果你只是从互联网上“复制粘贴”了一些教程,难怪你会遇到问题。通读 OpenGL 红皮书,让您真正了解程序的功能。 【参考方案1】:

当另一个窗口变为活动状态时发送 WM_ACTIVATE。当您说显示桌面时,没有其他窗口处于活动状态,因此从技术上讲,您的应用仍然处于活动状态,即使它已被最小化。

您可能想关注WM_WINDOWPOSCHANGED。您可以查看标志以了解它是什么类型的位置事件,或者您可以在窗口位置更改时检查IsIconic 和IsWindowVisible。

【讨论】:

嗯,我认为这将是正确的答案,但了解这些代码的实际含义会更有帮助(我收到的代码都没有在您链接的网站上)。看看我发布的代码,如果有什么要修复的。 WM_WINDOWPOSCHANGED 消息获取一个指向 WINDOWPOS 结构的指针(通过 LPARAM)。该结构的文档具有标志的含义。 msdn.microsoft.com/en-us/library/ms632612(v=vs.85).aspx 查看我发布的代码...我找到的代码都没有出现在该页面上。 (或者我只是瞎了眼?) 看起来我只是很愚蠢,但现在我知道如何阅读这些了。 0x1803 是个谜;我在文档中根本找不到 0x1000 或 0x0800。所以我想使用我拥有的当前代码可以吗? 您可以跳过尝试解码标志,并在每次出现此消息时检查 IsIconic 和 IsWindowVisible。这是一条不常见的消息,因此您并没有真正进行轮询,并且消息会在您关心的时间出现(当您的窗口变为隐藏或可见时)。【参考方案2】:

有多种潜在功能可能会根据您想要做的事情为您提供所需的信息:

GetForegroundWindow() :获取用户当前正在“工作”的窗口。如果您只想在用户使用您的应用程序而不是其他应用程序时绘制东西,则可以使用它。 GetActiveWindow() :返回调用线程中的活动窗口,这可能不是您想要的。如果您希望根据您自己的应用程序中哪个窗口处于活动状态来启用/禁用绘图,这可能会很有用。 GetFocus() :返回调用线程中具有当前键盘焦点的窗口。可能不是您想要的,请改用 GetForegorundWindow()。 IsWindowVisible():返回窗口的显示/隐藏标志是否设置为可见。这实际上并不能告诉您窗口是否真的在屏幕上可见。 GetTopWindow():告诉你 z 顺序中最高的窗口,但不告诉你它是否真的有焦点/前景。您的窗口可能会聚焦/激活/前景,但没有最高的 z 顺序(我认为无论如何)。

但是,从您的 cmets 来看,您似乎真的想看看您的窗口是否至少有一个像素在屏幕上实际可见。为此,我可能会使用this SO question 中提到的技术,使用奇怪的名称GetRandomRgn(),尽管更简单的检查可能是使用GetClipBox() 并检查NULLREGION 的返回码。

【讨论】:

知道是否有任何像素可见并不重要,重要的是它是否最小化。 WIN+D 按钮和“显示桌面”按钮没有给出最小化消息。检查我现在使用的代码的最新编辑。看看有什么需要改进的? 啊,我明白了。 IsIconic() 函数应该为您提供最小化状态,并且WM_SIZE 消息应该在更改最小化/最大化状态时传递到您的***窗口。如果您使用WM_WINDOWPOSCHANGED 保留当前编辑,您可能希望不使用硬编码常量,而是明确检查标志(请参阅msdn.microsoft.com/en-us/library/ms632612%28v=vs.85%29.aspx)。否则它可能大部分时间都有效,但并非一直有效,具体取决于传递给 WM_WINDOWPOSCHANGED 的确切标志。 你(和其他人)一直粘贴给我的链接没有解释我发现对我有用的那些代码:| 向下滚动页面并查看 flags 参数。 不,没有。检查自己:0x8130 0x1803 0x8120 没有找到。【参考方案3】:

在 Windows 8/10 中,还有另一个与 IsWindowVisible 不同的窗口可见性标志。检查 DwmGetWindowAttribute 和 DWMWA_CLOAKED 属性。

此外,窗口可以是半透明的,GetLayeredWindowAttributes 可以告诉您窗口的 alpha 级别是多少。

【讨论】:

【参考方案4】:

IsWindowVisible 告诉您您的窗口是否可见。 GetTopWindow 告诉你它是否是 Z 顺序中最上面的一个。

【讨论】:

你知道不需要我不时调用该函数的方法吗?就像我现在使用的 case WM_ACTIVATE: 一样。 更不用说我尝试了 IsWindowVisible() 并且它似乎也没有捕捉到WIN+D。 (除非我的项目目前专注于) “GetTopWindow 告诉你它是否是 Z 顺序中最上面的那个。” - 这不是 documentation 所说的:“检查 Z 顺序与指定父窗口关联的子窗口,并检索 Z 顺序顶部的 子窗口 的句柄。” OP 正在询问***窗口。跨度> 【参考方案5】:

试试 WM_ACTIVATEAPP。

如果来自任何其他应用程序的窗口获得焦点,wParam 将为 false。这包括按下“显示桌面”按钮。

【讨论】:

但这意味着即使我的渲染窗口顶部只有一些小窗口,我也会停止渲染?我不想那样做。只有当它完全隐藏时,我才想停止渲染。 没错,有点。它确实为您提供了一个地方来挂钩对 IsWindowVisible 之类的函数的调用。实际上,我没有看到有人提到过简单的 WM_SIZE 消息。我刚刚检查过,当按下“显示桌面”时,我的应用程序会获得 WM_SIZE。

以上是关于如何检查我的窗口是不是隐藏/可见?的主要内容,如果未能解决你的问题,请参考以下文章

如何检查元素是不是在屏幕上完全可见?

如何检测自动隐藏的任务栏是不是可见?

C# winform 检查控件是不是物理可见

当从隐藏变为可见时,如何阻止窗口短暂地重新出现在其最后一个可见位置?

一些JS运行后如何让Capybara检查可见性?

检查表格视图单元格是不是完全可见