托盘菜单
🌐 Tray Menu
本指南将带你了解如何创建一个带有自定义上下文菜单的系统托盘图标。
🌐 This guide will take you through the process of creating an icon with its own context menu to the system tray.
创建托盘图标
🌐 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 文档的 平台注意事项 部分。
最小化到托盘
🌐 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.
app.on('window-all-closed', () => {
// having this listener active will prevent the app from quitting.
})
附加上下文菜单
🌐 Attaching a context menu
你可以通过将一个 Menu 实例传递给 tray.setContextMenu 函数,将上下文菜单附加到托盘对象上。
🌐 You can attach a context menu to the Tray object by passing in a Menu instance
into the tray.setContextMenu function.
与常规的上下文菜单不同,托盘上下文菜单不需要使用 menu.popup API 进行手动配置。相反,托盘对象会为你处理点击事件(尽管该 API 上存在各种与点击相关的事件,用于高级用例)。
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)
})
要了解有关在 Electron 中制作菜单的更多信息,请参阅 Menus 指南。
在 macOS 上,enabled 和 visibility 属性在托盘的顶层菜单项中不可用。
可运行的 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.
- main.js
- index.html
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()
})
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<title>Tray Menu Demo</title>
</head>
<body>
<h1>Tray Menu Demo</h1>
<p>This app will stay running even after all windows are closed.</p>
<ul>
<li>Use the "Open App" menu item to focus the main window (or open one if it does not exist).</li>
<li>Change between red and green Tray icons with the "Set Green Icon" checkbox.</li>
<li>Give the Tray icon a title using the "Set Title" checkbox.</li>
<li>Quit the app using the "Quit" menu item.</li>
</ul>
</body>
</html>