通知和通知区域

通知区域是任务栏的一部分,可提供通知和状态的临时源。 它还可用于显示桌面上不存在的系统和程序功能的图标,例如电池电量、音量控制和网络状态。 通知区域过去称为系统托盘或状态区域。

本主题包含以下各节:

通知和通知区域指南

请参阅 Windows 用户体验交互指南通知通知区域部分,了解使用通知和通知区域的最佳做法。 目标是通过适当使用通知来提供用户权益,而不会让人烦恼或分心。

通知区域不适用于提供必须立即采取措施的关键信息。 它也不用于快速程序或命令访问。 从 Windows 7 开始,大部分功能都是通过应用程序的任务栏按钮实现的。

Windows 7 允许用户在选择时禁止应用程序的所有通知,因此经过深思熟虑的通知设计和使用将使用户倾向于允许应用程序继续显示它们。 通知是一种干扰;确保它们是值得的。

Windows 7 引入了“免打扰时间”的概念。 免打扰时间定义为新用户首次或操作系统升级或干净安装之后首次登录其帐户后的第一小时。 留出这段时间是为了让用户探索和熟悉新环境,而不会受到通知的干扰。 在此期间,不应该发送或显示大多数通知。 例外情况包括用户期望看到的对用户操作的响应的反馈,例如当他或她插入 USB 设备或打印文档时。 本主题稍后将讨论有关免打扰时间的 API 细节。

创建和显示通知

本主题中的其余部分概述了向用户显示应用程序通知时要遵循的基本过程。

  1. 添加通知图标
  2. 定义 NOTIFYICONDATA 版本
  3. 定义通知外观和内容
  4. 检查用户状态
  5. 显示通知
  6. 删除图标

添加通知图标

若要显示通知,通知区域中必须具有图标。 在某些情况下(如 Microsoft Communicator 或电池电量),该图标已经存在。 然而,在许多其他情况下,您只会在需要显示通知时才将图标添加到通知区域。 在任一情况下,这都是使用 Shell_NotifyIcon 函数完成的。 Shell_NotifyIcon 允许你在通知区域中添加、修改或删除图标。

包含三个图标的通知区域

将图标添加到 Windows 7 上的通知区域时,默认情况下会将其添加到通知区域的溢出部分中。 该区域包含处于活动状态但在通知区域中不可见的通知区域图标。 尽管在某些情况下系统可以暂时将图标提升到通知区域以供短暂预览(不足一分钟),但只有用户才能将图标从溢出区域提升到通知区域。

注意

用户应该最终说明他们希望在通知区域中看到哪些图标。 在通知区域中安装非暂时性图标之前,应该要求用户获得权限。 还应提供从通知区域删除图标的选项(通常通过快捷菜单来提供)。

 

在调用 Shell_NotifyIcon 时发送的 NOTIFYICONDATA 结构包含指定通知区域图标和通知本身的信息。 以下是特定于可以通过 NOTIFYICONDATA 设置的通知区域图标本身的那些项。

  • 从中获取图标的资源。
  • 图标的唯一标识符。
  • 图标工具提示的样式。
  • 通知区域中图标的状态(隐藏和/或共享)。
  • 与图标关联的应用程序窗口的句柄。
  • 一个回调消息标识符,此标识符允许图标与关联的应用程序窗口传达图标边界矩形和气球通知中发生的事件。 可以通过 Shell_NotifyIconGetRect 检索图标的边界矩形。

可以通过以下两种方式标识通知区域中的每个图标:

  • 在注册表中声明图标所用的 GUID。 这是 Windows 7 及更高版本上的首选方法。
  • 与通知区域图标关联的窗口的句柄,以及应用程序定义的图标标识符。 此方法在 Windows Vista 及更早版本上使用。

通知区域中的图标可以具有工具提示。 工具提示可以是标准工具提示(首选)或应用程序绘制的弹出 UI。 虽然不需要工具提示,但建议使用工具提示。

通知区域图标应该能够感知高 DPI。 应用程序应在其资源文件中同时提供 16x16 像素的图标和 32x32 像素的图标,然后使用 LoadIconMetric 确保正确加载和缩放正确的图标。

负责通知区域图标的应用程序应处理该图标的鼠标单击。 当用户右键单击图标时,它应显示一个普通快捷菜单。 但是,单击鼠标左键的结果将因图标的功能而异。 它应该以最适合该内容的形式显示用户期望看到的内容 - 弹出窗口、对话框或程序窗口本身。 例如,它可以显示状态图标的状态文本或音量控件的滑块。

单击所产生的弹出窗口或对话框的位置应放在通知区域中单击的坐标附近。 使用 CalculatePopupWindowPosition 确定其位置。

只需定义特定于图标的 NOTIFYICONDATA 成员(如上所述)并调用Shell_NotifyIcon,便可以将该图标添加到通知区域中而不显示通知,如下所示:

NOTIFYICONDATA nid = {};
// Do NOT set the NIF_INFO flag.
...                    
Shell_NotifyIcon(NIM_ADD, &nid);

你还可以将图标添加到通知区域中,并在一次调用 Shell_NotifyIcon 中显示通知。 为此,请继续阅读本主题中的说明。

定义 NOTIFYICONDATA 版本

随着 Windows 的发展,NOTIFYICONDATA 结构已经扩展,以包含更多成员来定义更多功能。 常量用于声明与通知区域图标一起使用哪个版本的 NOTIFYICONDATA,以实现向后兼容。 除非有令人信服的理由这样做,否则强烈建议你使用 Windows Vista 中引入的 NOTIFYICON_VERSION_4 版本。 此版本提供了完整的可用功能,包括通过注册的 GUID 识别通知区域图标的首选功能、卓越的回调机制和更好的辅助功能。

通过以下调用设置版本:

NOTIFYICONDATA nid = {};
... 
nid.uVersion = NOTIFYICON_VERSION_4;
// Add the icon
Shell_NotifyIcon(NIM_ADD, &nid);
// Set the version
Shell_NotifyIcon(NIM_SETVERSION, &nid);

请注意,对 Shell_NotifyIcon 的此调用不会显示通知。

定义通知外观和内容

通知是特殊类型的气球工具提示控件。 它包含标题、正文文本和图标。 与窗口一样,它的右上角有一个关闭按钮。 它还包含一个选项按钮,此按钮用于打开控制面板中的“通知区域图标”项,以允许用户显示或隐藏图标或仅显示通知而不显示图标。

通知气球的屏幕截图指示电池电量较低

在调用 Shell_NotifyIcon 时发送的 NOTIFYICONDATA 结构包含指定通知区域图标和通知气球本身的信息。 以下是特定于可以通过 NOTIFYICONDATA 设置的通知的那些项。

  • 由通知类型指定的通知气球中显示的图标。 可以指定图标的大小以及自定义图标。
  • 通知标题。 该标题的最大长度应为 48 个英文字符(以适应本地化需求)。 标题是通知的第一行,通过使用字体大小、颜色和粗细来区分。
  • 通知正文中使用的文本。 此文本最多应包含 200 个英文字符(以适应本地化需求)。
  • 通知不能立即显示时是否应丢弃该通知。
  • 通知的超时。 Windows Vista 及更高版本系统会忽略此设置,而采用系统范围的辅助功能超时设置。
  • 通知是否应考虑通过 NIIF_RESPECT_QUIET_TIME 标志设置的免打扰时间。

注意

IUserNotificationIUserNotification2 接口是 Shell_NotifyIcon 的组件对象模型 (COM) 包装器。 但是,目前,它们不提供直接通过 Shell_NotifyIcon 获得的完整 NOTIFYICON_VERSION_4 功能,包括使用 GUID 来识别通知区域图标。

 

检查用户状态

系统使用 SHQueryUserNotificationState 函数,此函数用于检查用户是处于免打扰时间、远离计算机还是处于不中断状态(如演示文稿模式)。 系统是否显示通知取决于此状态。

注意

如果你的应用程序正在使用的自定义通知方法并不使用 Shell_NotifyIconIUserNotificationIUserNotification2,则它应该始终明确调用 SHQueryUserNotificationState 来确定是否应该在当时显示通知 UI。

 

用户离开时发送的通知会排队等待显示,但因为你无法知道用户何时返回或通知当时是否仍然有效,所以你可能需要考虑稍后重新发送通知。

在免打扰时间发送的通知将被丢弃而不显示。 设计准则要求所有通知都可以被忽略。 它们不应要求用户立即执行操作。 因此,任何通知的重要性都不应忽视免打扰时间。

显示通知

设置了 NOTIFYICONDATA 版本并在 NOTIFYICONDATA 结构中定义了通知后,就可以调用 Shell_NotifyIcon 来显示图标。

  • 如果通知区域图标不存在,请调用 Shell_NotifyIcon 来添加此图标。 请针对暂时和非暂时性图标执行此操作。

    NOTIFYICONDATA nid = {};
    ...                    
    Shell_NotifyIcon(NIM_ADD, &nid);
    
  • 如果通知区域图标已存在,请调用 Shell_NotifyIcon 来修改此图标。

    NOTIFYICONDATA nid = {};
    ...                    
    Shell_NotifyIcon(NIM_MODIFY, &nid);
    

以下代码显示了设置 NOTIFYICONDATA 数据并通过 Shell_NotifyIcon 发送此数据的示例。 请注意,此示例通过 GUID(Windows 7 中首选)来标识通知图标。

// Declare NOTIFYICONDATA details. 
    // Error handling is omitted here for brevity. Do not omit it in your code.
    
    NOTIFYICONDATA nid = {};
    nid.cbSize = sizeof(nid);
    nid.hWnd = hWnd;
    nid.uFlags = NIF_ICON | NIF_TIP | NIF_GUID;
    
    // Note: This is an example GUID only and should not be used.
    // Normally, you should use a GUID-generating tool to provide the value to
    // assign to guidItem.
    static const GUID myGUID = 
    {0x23977b55, 0x10e0, 0x4041, {0xb8, 0x62, 0xb1, 0x95, 0x41, 0x96, 0x36, 0x69}};
    nid.guidItem = myGUID;
    
    // This text will be shown as the icon's tooltip.
    StringCchCopy(nid.szTip, ARRAYSIZE(nid.szTip), L"Test application");
    
    // Load the icon for high DPI.
    LoadIconMetric(hInst, MAKEINTRESOURCE(IDI_SMALL), LIM_SMALL, &(nid.hIcon));
    
    // Show the notification.
    Shell_NotifyIcon(NIM_ADD, &nid) ? S_OK : E_FAIL;

删除图标

若要删除图标,例如,当您仅临时添加图标来广播通知时,请调用 Shell_NotifyIcon,如下所示。 此调用中只需要一个标识图标的最小 NOTIFYICONDATA 结构即可。

NOTIFYICONDATA nid = {};
...                    
Shell_NotifyIcon(NIM_DELETE, &nid);

注意

卸载应用程序后,其通知区域图标仍然可以作为控制面板内通知区域图标页面中的一个选项向用户显示长达七天。 但是,所做的任何更改都不起作用。

 

SDK 示例

有关使用 Shell_NotifyIcon 的完整示例,请参阅 Windows 软件开发工具包 (SDK) 中的 NotificationIcon 示例

Shell_NotifyIcon

Shell_NotifyIconGetRect

NOTIFYICONDATA

SHQueryUserNotificationState

IUserNotification

IUserNotification2

任务栏

任务栏扩展