单击通知图标时备用显示/隐藏窗口

发布于 2024-10-10 06:54:15 字数 1372 浏览 0 评论 0 原文

我正在 WPF 中实现 Windows 7/Vista 风格的通知区域(“系统托盘”)弹出应用程序。到目前为止,我已经写过我的工作 此处(确定通知图标的位置、禁用调整大小等)。

然而,有一个问题我还没有完全满意地解决:第二次单击通知图标时隐藏窗口。如果您单击(例如)Vista/7 中的音量图标来显示音量控制,请注意,当第二次单击该图标时,它会再次隐藏。

我处理窗口的 Deactivated 事件来隐藏窗口,当单击通知图标时,窗口确实被停用。但是,单击通知图标当然会显示并激活该窗口,因此最终发生的情况是,该窗口在鼠标按下时消失,并在释放鼠标时重新出现(完成鼠标单击事件)。

我的第一个想法是我可以使用通知图标的 MouseDown 事件(我正在使用 System.Windows.Forms.NotifyIcon)并检查窗口当时是否可见 - 如果是,我可以将其解释为用户单击再次点击通知图标即可隐藏窗口。不幸的是,在实际单击鼠标之前,MouseDown 事件似乎不会触发(换句话说,它的工作方式与 MouseClick 事件相同),此时窗口已被停用并因此隐藏。这似乎排除了这个解决方案。

我的下一个想法(以及我最终使用的方法)是在窗口停用时获取光标位置(GetCursorPos)并检查该点是否在通知图标的范围内。同时,我还使用 GetForegroundWindow 来查找当前活动的窗口 - 如果确实要单击通知图标,则它应该是任务栏(类名为 Shell_TrayWnd 的顶级窗口)或通知区域弹出窗口(类名为 NotifyIconOverflowWindow 的顶级窗口;仅限 Windows 7+)。简而言之,如果光标位于通知图标上并且通知区域处于活动状态,我假设用户按下通知图标以隐藏窗口。如果这些条件成立,则以下 MouseClick 事件将不会导致显示/激活窗口。

不过,此解决方案至少有一个问题:如果光标悬停在通知图标上并且用户按 Windows 键打开开始菜单(或使用 Windows 键 + 数字快捷键打开应用程序),我的程序将错误地将其解释为按下鼠标到通知图标(因为任务栏是通过这些键盘快捷键激活的)。这意味着下次用户实际单击通知图标时,将不会显示该窗口。 (再次单击通知图标就会显示它。)

我希望我所写的内容有意义;如果没有,我很乐意尝试进一步澄清情况。

我很想听听是否有人对如何解决这个问题有任何其他想法。

我怀疑这可能是不可能的:在我看来,本机 Windows 7 通知区域弹出应用程序本身使用了一个简单的计时器实现。如果窗口停用和鼠标单击之间的时间少于大约 2 秒,则在音量控件打开时单击(例如)音量图标只会关闭音量控件。将鼠标按住图标较长时间然后释放将再次显示音量控件,即使在按下鼠标之前它已打开。

I'm implementing a Windows 7/Vista-style notification area ('system tray') pop-up application in WPF. I've written about my work so far here (determining the notify icon's position, disabling resize, etc.).

There is one problem that I haven't solved quite to my satisfaction, however: hiding the window when the notify icon is clicked a second time. If you click (for example) the volume icon in Vista/7 to show the volume control, notice that it is hidden again when the icon is clicked a second time.

I handle the window's Deactivated event to hide the window, and the window is indeed deactivated when the notify icon is clicked. However, clicking the notify icon of course shows and activates the window, so what ends up happening is that the window disappears while the mouse is down and re-appears when the mouse is released (completing the mouse click event).

My first thought was that I might use the notify icon's MouseDown event (I'm using a System.Windows.Forms.NotifyIcon) and check whether the window is visible at that time - if it were, I could interpret it as the user clicking the notify icon a second time to hide the window. Unfortunately, the MouseDown event seems not to fire until the mouse has actually been clicked (in other words it works identically to the MouseClick event), by which time the window has already been deactivated and thus hidden. This seems to rule out this solution.

My next idea (and the approach I've ended up using) was to get the cursor position when the window is deactivated (GetCursorPos) and checking whether that point is within the notify icon's bounds. At the same time, I also use GetForegroundWindow to find the currently active window - if the notify icon is indeed to be clicked, it should either be the taskbar (the top-level window with class name Shell_TrayWnd) or the notification area fly-out (top-level window with class name NotifyIconOverflowWindow; Windows 7+ only). In short, if the cursor is over the notify icon and the notification area is active, I assume that the user mouse-downed the notify icon to hide the window. If these conditions are true, then the following MouseClick event will not result in the window being shown/activated.

This solution has at least one problem, though: if the cursor is hovering over the notify icon and the user presses the Windows key to open the start menu (or uses a Windows key + number shortcut to open an application), my program will wrongly interpret that as a mouse-down to the notify icon (because the taskbar is made active by those keyboard shortcuts). This means that the next time the user actually does click the notify icon, the window will not be shown. (Clicking the notify icon once more will show it.)

I hope what I've written makes some sense; if not, I'm happy to try and clarify the situation further.

I'm interested to hear if anyone has any other ideas about how to solve this.

I suspect that it might not be possible: it seems to me that the native Windows 7 notification area pop-up applications themselves use a simple timer implementation. Clicking on (for example) the volume icon when the volume control is open will only close the volume control if the time between the window deactivation and mouse click is less than about 2 seconds. Holding the mouse down on the icon for a longer period of time and then releasing will show the volume control again, even if it was open before the mouse-down.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

ヤ经典坏疍 2024-10-17 06:54:15

这不是音量控制窗口的工作原理。当您单击任意位置(包括通知图标)时,它就会消失。该图标不相关。这是一个标准的 Win32 技巧,它捕获鼠标,以便它可以看到窗口外的点击。

WPF 中的鼠标捕获。做起来并不那么容易,因为它需要 IInputElement 而不是窗口句柄。

That's not how the volume control window works. It disappears when you click anywhere, including the notification icon. The icon isn't relevant. This is a standard Win32 trick, it captures the mouse so it can see clicks outside of its window.

Mouse.Capture in WPF. Not nearly as easy to do because it requires an IInputElement instead of a window handle.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文