Skip to main content

托盘菜单

¥Tray Menu

本指南将指导你创建一个带有自身上下文菜单的系统托盘图标。

¥This guide will take you through the process of creating an icon with its own context menu to the system tray.

  • 在 macOS 上,图标将位于屏幕右上角的 菜单栏附加功能 区域。

    ¥On macOS, the icon will be located on the top right corner of your screen in the menu bar extras area.

  • 在 Windows 上,图标将位于任务栏末尾的 通知区域 中。

    ¥On Windows, the icon will be located in the notification area at the end of the taskbar.

  • 在 Linux 上,托盘的位置会根据你的桌面环境而有所不同。

    ¥On Linux, the location of the Tray will differ based on your desktop environment.

创建托盘图标

¥Creating a Tray icon

你的 Electron 应用的托盘图标需要使用 Tray 类的实例以编程方式创建。类构造函数需要一个 NativeImage 实例或兼容图标文件的路径。

¥The tray icon for your Electron app needs to be created programmatically with an instance of the Tray class. The class constructor requires a single instance of a NativeImage or a path to a compatible icon file.

[!注意] 文件格式因操作系统而异。更多详情,请参阅 Tray API 文档的 平台注意事项 部分。

¥[!NOTE] File formats vary per operating system. For more details, see the Platform Considerations section of the Tray API documentation.

最小化到托盘

¥Minimizing to tray

为了使应用和系统托盘图标在所有窗口关闭后仍保持活动状态,你需要在 app 模块上监听 window-all-closed 事件。基础 Electron 模板通常会监听此事件,但在 Windows 和 Linux 上会退出应用,以模拟标准操作系统行为。

¥In order to keep the app and the system tray icon alive even when all windows are closed, you need to have a listener for the window-all-closed event on the app module. The base Electron templates generally listen for this event but quit the app on Windows and Linux to emulate standard OS behavior.

Setting up minimize to tray
app.on('window-all-closed', () => {
// having this listener active will prevent the app from quitting.
})

附加上下文菜单

¥Attaching a context menu

你可以通过将 Menu 实例传递给 tray.setContextMenu 函数,将上下文菜单附加到 Tray 对象。

¥You can attach a context menu to the Tray object by passing in a Menu instance into the tray.setContextMenu function.

[!注意] 与常规 上下文菜单 不同,托盘上下文菜单不需要使用 menu.popup API 手动检测。Tray 对象会替你处理点击事件(尽管 API 中存在各种与点击相关的事件,用于高级用例)。

¥[!NOTE] Unlike with regular context menus, Tray context menus don't need to be manually instrumented using the menu.popup API. Instead, the Tray object handles click events for you (although various click-related events exist on the API for advanced use cases).

Creating a Tray menu that can quit the app
const { nativeImage } = require('electron/common')
const { app, Tray, Menu } = require('electron/main')

// save a reference to the Tray object globally to avoid garbage collection
let tray

// 16x16 red circle data URL
const icon = nativeImage.createFromDataURL('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAACTSURBVHgBpZKBCYAgEEV/TeAIjuIIbdQIuUGt0CS1gW1iZ2jIVaTnhw+Cvs8/OYDJA4Y8kR3ZR2/kmazxJbpUEfQ/Dm/UG7wVwHkjlQdMFfDdJMFaACebnjJGyDWgcnZu1/lrCrl6NCoEHJBrDwEr5NrT6ko/UV8xdLAC2N49mlc5CylpYh8wCwqrvbBGLoKGvz8Bfq0QPWEUo/EAAAAASUVORK5CYII=')

// The Tray can only be instantiated after the 'ready' event is fired
app.whenReady().then(() => {
tray = new Tray(icon)
const contextMenu = Menu.buildFromTemplate([
{ role: 'quit' }
])
tray.setContextMenu(contextMenu)
})

[!TIP] 要了解更多关于在 Electron 中制作菜单的信息,请参阅 菜单 指南。

¥[!TIP] To learn more about crafting menus in Electron, see the Menus guide.

[!WARNING] macOS 托盘中的顶层菜单项无法使用 enabledvisibility 属性。

¥[!WARNING] The enabled and visibility properties are not available for top-level menu items in the tray on macOS.

可运行的 Fiddle 演示

¥Runnable Fiddle demo

下面是一个可运行的示例,它将各种菜单项附加到托盘的上下文菜单,以帮助控制应用状态并与托盘 API 本身交互。

¥Below is a runnable example of attaching various menu items to the Tray's context menu that help control app state and interact with the Tray API itself.

const { app, BrowserWindow, Menu, Tray } = require('electron/main')
const { nativeImage } = require('electron/common')

// save a reference to the Tray object globally to avoid garbage collection
let tray = null

function createWindow () {
const mainWindow = new BrowserWindow()
mainWindow.loadFile('index.html')
}

// The Tray object can only be instantiated after the 'ready' event is fired
app.whenReady().then(() => {
createWindow()

const red = nativeImage.createFromDataURL('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAACTSURBVHgBpZKBCYAgEEV/TeAIjuIIbdQIuUGt0CS1gW1iZ2jIVaTnhw+Cvs8/OYDJA4Y8kR3ZR2/kmazxJbpUEfQ/Dm/UG7wVwHkjlQdMFfDdJMFaACebnjJGyDWgcnZu1/lrCrl6NCoEHJBrDwEr5NrT6ko/UV8xdLAC2N49mlc5CylpYh8wCwqrvbBGLoKGvz8Bfq0QPWEUo/EAAAAASUVORK5CYII=')
const green = nativeImage.createFromDataURL('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAACOSURBVHgBpZLRDYAgEEOrEzgCozCCGzkCbKArOIlugJvgoRAUNcLRpvGH19TkgFQWkqIohhK8UEaKwKcsOg/+WR1vX+AlA74u6q4FqgCOSzwsGHCwbKliAF89Cv89tWmOT4VaVMoVbOBrdQUz+FrD6XItzh4LzYB1HFJ9yrEkZ4l+wvcid9pTssh4UKbPd+4vED2Nd54iAAAAAElFTkSuQmCC')

tray = new Tray(red)
tray.setToolTip('Tray Icon Demo')

const contextMenu = Menu.buildFromTemplate([
{
label: 'Open App',
click: () => {
const wins = BrowserWindow.getAllWindows()
if (wins.length === 0) {
createWindow()
} else {
wins[0].focus()
}
}
},
{
label: 'Set Green Icon',
type: 'checkbox',
click: ({ checked }) => {
checked ? tray.setImage(green) : tray.setImage(red)
}
},
{
label: 'Set Title',
type: 'checkbox',
click: ({ checked }) => {
checked ? tray.setTitle('Title') : tray.setTitle('')
}
},
{ role: 'quit' }
])

tray.setContextMenu(contextMenu)
})

app.on('window-all-closed', function () {
// This will prevent the app from closing when windows close
})

app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})