## 使用 Electron 自定義菜單
使用 Menu 和 MenuItem 模塊可用于創建自定義本地菜單.
有兩種菜單: 應用程序(頂部)菜單和上下文(右鍵單擊)菜單.
在瀏覽器中打開 完整的 [API 文檔](http://electron.atom.io/docs/api/menu)
### 創建應用程序菜單
`支持: Win, macOS, Linux | 進程: Main`
使用 Menu 和 MenuItem 模塊可以自定義你的應用程序菜單. 如果沒有設置任何菜單, Electron 將為您的應用默認生成一個最小的菜單.
此應用程序使用下面的代碼設置應用程序菜單. 如果您點擊應用程序菜單中的 "查看" 選項, 然后點擊 "應用程序菜單演示", 則會顯示一個信息框.


主進程
```
const {BrowserWindow, Menu, app, shell, dialog} = require('electron')
let template = [{
label: '編輯',
submenu: [{
label: '撤銷',
accelerator: 'CmdOrCtrl+Z',
role: 'undo'
}, {
label: '重做',
accelerator: 'Shift+CmdOrCtrl+Z',
role: 'redo'
}, {
type: 'separator'
}, {
label: '剪切',
accelerator: 'CmdOrCtrl+X',
role: 'cut'
}, {
label: '復制',
accelerator: 'CmdOrCtrl+C',
role: 'copy'
}, {
label: '粘貼',
accelerator: 'CmdOrCtrl+V',
role: 'paste'
}, {
label: '全選',
accelerator: 'CmdOrCtrl+A',
role: 'selectall'
}]
}, {
label: '查看',
submenu: [{
label: '重載',
accelerator: 'CmdOrCtrl+R',
click: (item, focusedWindow) => {
if (focusedWindow) {
// 重載之后, 刷新并關閉所有之前打開的次要窗體
if (focusedWindow.id === 1) {
BrowserWindow.getAllWindows().forEach(win => {
if (win.id > 1) win.close()
})
}
focusedWindow.reload()
}
}
}, {
label: '切換全屏',
accelerator: (() => {
if (process.platform === 'darwin') {
return 'Ctrl+Command+F'
} else {
return 'F11'
}
})(),
click: (item, focusedWindow) => {
if (focusedWindow) {
focusedWindow.setFullScreen(!focusedWindow.isFullScreen())
}
}
}, {
label: '切換開發者工具',
accelerator: (() => {
if (process.platform === 'darwin') {
return 'Alt+Command+I'
} else {
return 'Ctrl+Shift+I'
}
})(),
click: (item, focusedWindow) => {
if (focusedWindow) {
focusedWindow.toggleDevTools()
}
}
}, {
type: 'separator'
}, {
label: '應用程序菜單演示',
click: function (item, focusedWindow) {
if (focusedWindow) {
const options = {
type: 'info',
title: '應用程序菜單演示',
buttons: ['好的'],
message: '此演示用于 "菜單" 部分, 展示如何在應用程序菜單中創建可點擊的菜單項.'
}
dialog.showMessageBox(focusedWindow, options, function () {})
}
}
}]
}, {
label: '窗口',
role: 'window',
submenu: [{
label: '最小化',
accelerator: 'CmdOrCtrl+M',
role: 'minimize'
}, {
label: '關閉',
accelerator: 'CmdOrCtrl+W',
role: 'close'
}, {
type: 'separator'
}, {
label: '重新打開窗口',
accelerator: 'CmdOrCtrl+Shift+T',
enabled: false,
key: 'reopenMenuItem',
click: () => {
app.emit('activate')
}
}]
}, {
label: '幫助',
role: 'help',
submenu: [{
label: '學習更多',
click: () => {
shell.openExternal('http://electron.atom.io')
}
}]
}]
function addUpdateMenuItems (items, position) {
if (process.mas) return
const version = app.getVersion()
let updateItems = [{
label: `版本 ${version}`,
enabled: false
}, {
label: '正在檢查更新',
enabled: false,
key: 'checkingForUpdate'
}, {
label: '檢查更新',
visible: false,
key: 'checkForUpdate',
click: () => {
require('electron').autoUpdater.checkForUpdates()
}
}, {
label: '重啟并安裝更新',
enabled: true,
visible: false,
key: 'restartToUpdate',
click: () => {
require('electron').autoUpdater.quitAndInstall()
}
}]
items.splice.apply(items, [position, 0].concat(updateItems))
}
function findReopenMenuItem () {
const menu = Menu.getApplicationMenu()
if (!menu) return
let reopenMenuItem
menu.items.forEach(item => {
if (item.submenu) {
item.submenu.items.forEach(item => {
if (item.key === 'reopenMenuItem') {
reopenMenuItem = item
}
})
}
})
return reopenMenuItem
}
if (process.platform === 'darwin') {
const name = app.getName()
template.unshift({
label: name,
submenu: [{
label: `關于 ${name}`,
role: 'about'
}, {
type: 'separator'
}, {
label: '服務',
role: 'services',
submenu: []
}, {
type: 'separator'
}, {
label: `隱藏 ${name}`,
accelerator: 'Command+H',
role: 'hide'
}, {
label: '隱藏其它',
accelerator: 'Command+Alt+H',
role: 'hideothers'
}, {
label: '顯示全部',
role: 'unhide'
}, {
type: 'separator'
}, {
label: '退出',
accelerator: 'Command+Q',
click: () => {
app.quit()
}
}]
})
// 窗口菜單.
template[3].submenu.push({
type: 'separator'
}, {
label: '前置所有',
role: 'front'
})
addUpdateMenuItems(template[0].submenu, 1)
}
if (process.platform === 'win32') {
const helpMenu = template[template.length - 1].submenu
addUpdateMenuItems(helpMenu, 0)
}
app.on('ready', () => {
const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)
})
app.on('browser-window-created', () => {
let reopenMenuItem = findReopenMenuItem()
if (reopenMenuItem) reopenMenuItem.enabled = false
})
app.on('window-all-closed', () => {
let reopenMenuItem = findReopenMenuItem()
if (reopenMenuItem) reopenMenuItem.enabled = true
})
```
### 創建上下文菜單
`支持: Win, macOS, Linux | 進程: Main`
可以使用 Menu 和 MenuItem 模塊創建上下文或右鍵單擊菜單. 您可以右鍵單擊此應用程序中的任何位置, 或單擊示例按鈕以查看示例上下文菜單.
在這個示例中, 我們使用 ipcRenderer 模塊來展示從渲染器進程顯式調用它時的上下文菜單.
有關所有可用的屬性請查看 [上下文菜單事件文檔](http://electron.atom.io/docs/api/web-contents/#event-context-menu)

主進程
```
const {
BrowserWindow,
Menu,
MenuItem,
ipcMain,
app
} = require('electron')
const menu = new Menu()
menu.append(new MenuItem({ label: 'Hello' }))
menu.append(new MenuItem({ type: 'separator' }))
menu.append(new MenuItem({ label: 'Electron', type: 'checkbox', checked: true }))
app.on('browser-window-created', (event, win) => {
win.webContents.on('context-menu', (e, params) => {
menu.popup(win, params.x, params.y)
})
})
ipcMain.on('show-context-menu', (event) => {
const win = BrowserWindow.fromWebContents(event.sender)
menu.popup(win)
})
```
渲染器進程
```
showConMenu () {
const ipcRenderer = require('electron').ipcRenderer
ipcRenderer.send('show-context-menu')
}
```
## 使用 Electron 注冊鍵盤快捷鍵
可以使用 globalShortcut 和 Menu 模塊定義鍵盤快捷鍵.
在 Electron 中, 鍵盤快捷鍵被稱作加速器(Accelerator). 它們可以分配到應用程序菜單中的操作上, 也可以全局分配,所以即使你的應用程序沒有獲得鍵盤焦點, 它們也可以被觸發.
在瀏覽器中查看[Menu](http://electron.atom.io/docs/api/menu),[Accelerator](http://electron.atom.io/docs/api/accelerator) 和 [globalShortcut](http://electron.atom.io/docs/api/global-shortcut) API 的完整文檔.
### 注冊全局鍵盤快捷鍵
`支持: Win, macOS, Linux | 進程: Main`
試一下這個示例, 在鍵盤上按下 Command或Control+Alt+K 快捷鍵.
即使應用程序沒有鍵盤焦點, 也會檢測到全局快捷鍵, 而且它們必須在應用程序的 ready 事件發出后注冊.

主進程
```
const {app, dialog, globalShortcut} = require('electron')
app.on('ready', () => {
globalShortcut.register('CommandOrControl+Alt+K', () => {
dialog.showMessageBox({
type: 'info',
message: '成功!',
detail: '你按下了一個全局注冊的快捷鍵綁定.',
buttons: ['好的']
})
})
})
app.on('will-quit', () => {
globalShortcut.unregisterAll()
})
```