【问题标题】:How to change native menu of electron-quick-start example app如何更改电子快速启动示例应用程序的本机菜单
【发布时间】:2026-01-23 14:40:02
【问题描述】:

electron 应用打开时使用与 electron-quick-start 示例应用中相同的默认菜单以及如何更改它? 还尝试了menu example on the docs,但没有任何变化。 当我用mainWindow.setMenu(null); 隐藏菜单时,菜单消失了,但仍然无法初始化新菜单

有什么想法吗?

平台:Windows 7

电子版:0.36.4

参考文件:

package.json:

{
  "name": "electric_timer",
  "version": "0.1.0",
  "description": "a Time sheet & project managment",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "none"
  },
  "author": "Eyal Ron",
  "license": "MIT"
}

app.js:

var app = require('app');
var BrowserWindow = require('browser-window');

app.on('ready', function (){
  var mainWindow = new BrowserWindow({
    width: 800,
    height: 600
  });
  mainWindow.setMenu(null);
  mainWindow.loadUrl('file://' + __dirname + '/main.html');
});

main.js:

var remote = require('remote');
var Menu = remote.require('menu');

var menu = Menu.buildFromTemplate([
  {
    label: 'Electron',
    submenu: [
      {
        label: 'Prefs',
        click: function(){
          alert('hello menu');
        }
      }
    ]
  }
]);
Menu.setApplicationMenu(menu);

main.html:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>electron test</title>
</head>
<body>
  <h1>hello world</h1>
  <script>requier('./main.js')</script>
</body>
</html>

【问题讨论】:

    标签: javascript menu electron


    【解决方案1】:

    Electron 的 'default_app' sets the menu;如果您想避免这种情况,您需要 Electron 直接启动您的应用程序,而不是通过默认应用程序(注意:如果您使用 electron . 之类的内容启动您的应用程序,您实际上是启动了默认应用程序)。

    Electron looks in its resource folder 用于“app”、“app.asar”或“default_app”,因此要直接启动您的应用,您需要将其复制或链接到 Electron 的资源文件夹。

    无论您如何启动您的应用程序,您都可以使用 Menu.setApplicationMenu 设置您的菜单——您可以在主进程中执行此操作,而无需像您的示例中那样在渲染器中执行此操作。顺便说一句,您的 main.html 中有一个错字(requier 而不是 require),所以如果这是您的实际代码,则表明您的 main.js 根本没有运行。

    【讨论】:

    • 我认为这是一个很好的解释,但不是一个很好的答案。你没有回答的是,如果你正在开发一个 Electron 应用程序,你如何看到你的菜单,具体来说,你如何直接启动应用程序?
    【解决方案2】:

    将自定义菜单的逻辑放入您的app('ready') 事件回调。试试下面的代码示例

    const {app, BrowserWindow, Menu} = require('electron');
    let mainWindow;
    let menuTemplate = [
        {
            label: "Window Manager",
            submenu: [
                { label: "create New" }
            ]
        },
        {
          label : "View",
                submenu : [
            { role : "reload" },
            { label : "custom reload" }
            ]
        }
    ];
    function appInit () {
      // Create the browser window.
      mainWindow = new BrowserWindow({width: 800, height: 600})
    
      // and load the main.html of the app.
      mainWindow.loadFile('main.html')
    
        let menu = Menu.buildFromTemplate(menuTemplate);
        Menu.setApplicationMenu(menu);
    }
    app.on('ready', () => {
      appInit();
    })
    

    【讨论】:

    • 您在全局范围内声明menuTemplate 的任何特殊原因?如果 mainWindow 不在全局范围内,垃圾收集是否会像使用 mainWindow 一样摆脱它?
    • 没有特别的理由这样做。菜单模板也可以保存在单独的 const 文件中,并根据项目的平台和环境进行自定义。
    • 为什么不在使用它的函数中声明呢?
    • 如前所述,没有强迫症。 Post 仅提供了一个使用菜单模板的示例,以使其在整个文件中可重用。菜单模板可以在任何地方声明或动态构建。
    • 有趣的好吧
    【解决方案3】:

    看起来电子 Menu 和 MenuItem 对象被设置为不可变的。

    这意味着如果你想修改它们,你必须创建新对象并使用它。这就是我的代码所做的,隐藏帮助菜单和开发者工具:

    // main.js
    
    function createWindow () {
      // Create the browser window.
      mainWindow = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
          preload: path.join(__dirname, 'preload.js')
        }
      })
    
    ...
    
      let defaultMenu = Menu.getApplicationMenu()
    
      let newMenu = new Menu();
      defaultMenu.items
        .filter(x => x.role != 'help')
        .forEach(x => {
          if(x.role == 'viewmenu' && process.env.NODE_ENV == 'production') {
            let newSubmenu = new Menu();
    
            x.submenu.items.filter(y => y.role != 'toggledevtools').forEach(y => newSubmenu.append(y));
    
            x.submenu = newSubmenu;
    
            newMenu.append(
              new MenuItem({
                type: x.type,
                label: x.label,
                submenu: newSubmenu
              })
            );
          } else {
            newMenu.append(x);
          }
        })
    
      Menu.setApplicationMenu(newMenu);
    
    ...
      })
    }
    
    app.on('ready', createWindow)
    
    

    【讨论】:

      【解决方案4】:

      Electron 在您的应用中的什么位置?您的package.json 文件应如下所示:

      {
        "name": "todos",
        "version": "1.0.0",
        "description": "",
        "main": "index.js",
        "scripts": {
          "electron": "electron ."
        },
        "author":
          "Who Cares <email@example.com> (https://doesntmatter.com/)",
        "license": "MIT",
        "dependencies": {
          "electron": "3.0.8"
        }
      }
      

      您的 Electron 端将如下所示:

      const electron = require('electron');
      const { app, BrowserWindow, Menu } = electron;
      
      let mainWindow;
      
      app.on('ready', () => {
        mainWindow = new BrowserWindow({});
        mainWindow.loadURL(`file://${__dirname}/main.html`);
      
        const mainMenu = Menu.buildFromTemplate(menuTemplate);
        Menu.setApplicationMenu(mainMenu);
      });
      
      const menuTemplate = [
        {
          label: 'File'
        }
      ];
      

      即使修复了语法,您仍然会遇到接管默认 Electron 菜单及其键绑定的问题。您是说您将添加自己的自定义菜单和键绑定,如果这是您的目标,那么在生产中就可以了,但听起来您失去了想要维护的功能。

      你可以这样修复它:

      const menuTemplate = [
        {
          label: 'File',
          submenu: [{ label: 'New Todo' }]
        }
      ];
      

      【讨论】:

        最近更新 更多