【问题标题】:Electron.js How to minimize/close window to system tray and restore window back from tray?Electron.js 如何最小化/关闭系统托盘的窗口并从托盘恢复窗口?
【发布时间】:2016-06-15 07:27:12
【问题描述】:

我希望我的Electron.js 应用程序存在于系统托盘上,并且每当用户想要做某事时,他们可以从系统托盘恢复做某事并将其最小化/关闭回到系统托盘。我该怎么做?

我从文档中看到了tray 部分,但对实现我想要的没有太大帮助。

这是我目前在main.js 文件中得到的信息

var application = require('app'),
    BrowserWindow = require('browser-window'),
    Menu = require('menu'), 
    Tray = require('tray'); 
application.on('ready', function () {
    var mainWindow = new BrowserWindow({
        width: 650,
        height: 450,
        'min-width': 500,
        'min-height': 200,
        'accept-first-mouse': true,
        // 'title-bar-style': 'hidden',
        icon:'./icon.png'
    });
    mainWindow.loadUrl('file://' + __dirname + '/src/index.html');
    mainWindow.on('closed', function () {
        mainWindow = null;
    });
    mainWindow.setMenu(null);

    var appIcon = null;
    appIcon = new Tray('./icon-resized.png');
    var contextMenu = Menu.buildFromTemplate([
        { label: 'Restore', type: 'radio' }
    ]);
    appIcon.setToolTip('Electron.js App');
    appIcon.setContextMenu(contextMenu);
});

更新:

我找到了这个menubar repo,但它在 linux 上无法正常工作。

【问题讨论】:

    标签: javascript node.js electron nw.js


    【解决方案1】:

    实际上我很久以前就知道了,但是对于遇到同样问题的人来说,这是一种可以实现最小化到 tray 并从 tray 恢复的方法。诀窍是捕捉closeminimize 事件。

    var BrowserWindow = require('browser-window'),
    
    var mainWindow = new BrowserWindow({
        width: 850,
        height: 450,
        title: "TEST",
        icon:'./icon.png'
    });
    
    mainWindow.on('minimize',function(event){
        event.preventDefault();
        mainWindow.hide();
    });
    
    mainWindow.on('close', function (event) {
        if(!application.isQuiting){
            event.preventDefault();
            mainWindow.hide();
        }
    
        return false;
    });
    

    并从Tray恢复

    var contextMenu = Menu.buildFromTemplate([
        { label: 'Show App', click:  function(){
            mainWindow.show();
        } },
        { label: 'Quit', click:  function(){
            application.isQuiting = true;
            application.quit();
        } }
    ]);
    

    【讨论】:

    • 这里的“应用”是什么意思?
    • 我收到错误无法设置未定义的属性“isQuiting”
    • @AnandVaidya: var { application } = require('electron');
    • 两件事,A)这可能会导致电子更新程序和电子生成器的严重错误。 electron 更新程序有一个名为 quitAndInstall() 的函数,正如您猜测的那样,它会在发布时退出并安装您的电子应用程序的更新。 quitAndInstall 函数显然使用了电子的 quit() 函数,该函数在这里几乎被阻止,所以无论谁使用它,如果您不想为您的客户发布损坏的更新,请在使用 quitAndInstall() 之前使您的 isQuiting 值真实。跨度>
    • B) 我真的不认为将密钥和值附加到电子对象上是一个好习惯。为什么不在全局范围内使用变量?
    【解决方案2】:

    除了上述答案 - isQuiting 标志也值得在应用程序的 before-quit 回调中设置。这样,如果操作系统或用户以其他方式请求,应用程序将正确关闭,例如通过 Macos Dock 任务栏的退出命令。完成 Typescript 友好的 sn-p:

    import {app, BrowserWindow, Tray, Menu} from 'electron';
    import * as path from 'path';
    
    let window;
    let isQuiting;
    let tray;
    
    app.on('before-quit', function () {
      isQuiting = true;
    });
    
    app.on('ready', () => {
      tray = new Tray(path.join(__dirname, 'tray.png'));
    
      tray.setContextMenu(Menu.buildFromTemplate([
        {
          label: 'Show App', click: function () {
            window.show();
          }
        },
        {
          label: 'Quit', click: function () {
            isQuiting = true;
            app.quit();
          }
        }
      ]));
    
      window = new BrowserWindow({
        width: 850,
        height: 450,
        show: false,
      });
    
      window.on('close', function (event) {
        if (!isQuiting) {
          event.preventDefault();
          window.hide();
          event.returnValue = false;
        }
      });
    });
    

    【讨论】:

      【解决方案3】:

      如果你想一直在系统托盘上显示图标直到你不退出应用程序,我用一个场景更新了代码

      var { app, BrowserWindow, Tray, Menu } = require('electron')
      var path = require('path')
      var url = require('url')
      var iconpath = path.join(__dirname, 'user.ico') // path of y
      var win
      function createWindow() {
          win = new BrowserWindow({ width: 600, height: 600, icon: iconpath })
      
          win.loadURL(url.format({
              pathname: path.join(__dirname, 'index.html'),
          }))
      
          var appIcon = new Tray(iconpath)
      
          var contextMenu = Menu.buildFromTemplate([
              {
                  label: 'Show App', click: function () {
                      win.show()
                  }
              },
              {
                  label: 'Quit', click: function () {
                      app.isQuiting = true
                      app.quit()
                  }
              }
          ])
      
          appIcon.setContextMenu(contextMenu)
      
          win.on('close', function (event) {
              win = null
          })
      
          win.on('minimize', function (event) {
              event.preventDefault()
              win.hide()
          })
      
          win.on('show', function () {
              appIcon.setHighlightMode('always')
          })
      
      }
      
      app.on('ready', createWindow)
      

      【讨论】:

      • // Deprecated tray.setHighlightMode(mode) // API will be removed in v7.0 without replacement.
      【解决方案4】:

      比使用标志更好的方法,并且对于那些不想改变 minimize 行为的人来说:

      通常使用mainWindow.hide() 隐藏close 事件的窗口

      mainWindow.on('close', function (event) {
          event.preventDefault();
          mainWindow.hide();
      });
      

      然后调用mainWIndow.destroy() 强制关闭窗口。它还保证执行closed 事件处理程序。

      来自the documentation

      强制关闭窗口,网页不会触发unload和beforeunload事件,该窗口也不会触发close事件,但保证会触发close事件。

      var contextMenu = Menu.buildFromTemplate([
          { label: 'Show App', click:  function(){
              mainWindow.show();
          } },
          { label: 'Quit', click:  function(){
              mainWindow.destroy();
              app.quit();
          } }
      ]);
      

      【讨论】:

      • 这对我来说效果更好,因为使用标志不是 typescript 的选项
      【解决方案5】:

      我分享了我的 Sketch,在任务栏图标上最小化隐藏,菜单选项右击图标来恢复/关闭。使用 websocket/http 服务器..

      //const {app, BrowserWindow} = require('electron');
      const {app, BrowserWindow, Tray, Menu} = require('electron');
      const myip = require('quick-local-ip');
      const express = require('express');
      const WebSocket = require('ws');
      const bodyParser = require('body-parser');
      const path = require('path')
      // Config
      const Config = {
          http_port: '8080',
          socket_port: '3030'
      };
      
      var iconpath = path.join(__dirname, 'rfid.png') // path of y
      
      // Http server
      const _app = express();
      const server = require('http').Server(_app);
      server.listen(Config.http_port);
      
      // WSS server
      const wss = new WebSocket.Server({port: Config.socket_port});
      
      // Console print
      console.log('[SERVER]: WebSocket on: ' + myip.getLocalIP4() + ':' + Config.socket_port); // print websocket ip address
      console.log('[SERVER]: HTTP on: ' + myip.getLocalIP4() + ':' + Config.http_port); // print web server ip address
      
      // Keep a global reference of the window object, if you don't, the window will
      // be closed automatically when the JavaScript object is garbage collected.
      let mainWindow;
      
      let window;
      let isQuiting;
      let tray;
      
      function createWindow() {
          mainWindow = new BrowserWindow({
              width: 1200,
              height: 800,
              acceptFirstMouse: true,
              autoHideMenuBar: false,
              useContentSize: true,
          });
      
          var appIcon = new Tray(iconpath);
      
          // mainWindow.loadURL('index.html')
          mainWindow.loadURL('http://localhost:8080');
          mainWindow.focus();
          // mainWindow.setFullScreen(true);
      
          // Open the DevTools.
          mainWindow.webContents.openDevTools();
      
          var contextMenu = Menu.buildFromTemplate([
              {
                  label: 'Show App', click: function () {
                      mainWindow.show()
                  }
              },
              {
                  label: 'Quit', click: function () {
                      app.isQuiting = true
                      app.quit()
                  }
              }
          ])
      
          appIcon.setContextMenu(contextMenu)
      
          // Emitted when the window is closed.
          mainWindow.on('close', function (event) {
              mainWindow = null
          });
      
          mainWindow.on('minimize', function (event) {
              event.preventDefault()
              mainWindow.hide()
          });
      
          mainWindow.on('show', function () {
              appIcon.setHighlightMode('always')
          })
      }
      
      app.on('ready', createWindow)
      
      // Quit when all windows are closed.
      app.on('window-all-closed', function () {
          // On OS X it is common for applications and their menu bar
          // to stay active until the user quits explicitly with Cmd + Q
          if (process.platform !== 'darwin') {
              app.quit()
          }
      })
      
      app.on('activate', function () {
          // On OS X it's common to re-create a window in the app when the
          // dock icon is clicked and there are no other windows open.
          if (mainWindow === null) {
              createWindow()
          }
      })
      
      /**
       * EXPRESS
       */
      _app.use(bodyParser.urlencoded({
          extended: false
      }));
      
      _app.use('/assets', express.static(__dirname + '/www/assets'))
      
      _app.get('/', function (req, res) {
          res.sendFile(__dirname + '/www/index.html');
      });
      
      /**
       * WEBSOCKET
       */
      wss.getUniqueID = function () {
          function s4() {
              return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
          }
      
          return s4() + s4() + '-' + s4();
      };
      
      wss.on('connection', function connection(ws, req) {
          ws.id = wss.getUniqueID();
          console.log('[SERVER]: Client Connected. ID=', ws.id);
      
          ws.on('close', function close() {
              console.log('[SERVER]: Client disconnected.');
          });
      
          ws.on('message', function incoming(recieveData) {
              console.log('[SERVER] Message:', recieveData);
      
              // Example use
              // send(recieveData);
      
              sendAll(recieveData);
          });
      
          // Send back to client
          function send(data) {
              data = JSON.stringify(data);
              ws.send(data);
          }
      
          // Send to all clients
          function sendAll(data) {
              data = JSON.stringify(data);
      
              wss.clients.forEach(function each(client) {
                  client.send(data);
              });
          }
      });
      

      【讨论】:

        【解决方案6】:

        这是用 NW.js 标记的,因为所有其他答案都是针对 Electron 的,所以我想我会展示 NW.js 中的一切总是多么容易。这里有一个简单的演示仓库:

        只需下载并运行npm install && npm start

        【讨论】:

          【解决方案7】:

          尝试最小化事件而不是隐藏。

          var BrowserWindow = require('browser-window'),
          
          var mainWindow = new BrowserWindow({
              width: 850,
              height: 450,
              title: "TEST",
              icon:'./icon.png'
          });
          
          mainWindow.on('minimize',function(event){
              event.preventDefault();
              mainWindow.minimize();
          });
          
          mainWindow.on('close', function (event) {
          
            event.preventDefault();
            mainWindow.minimize();
              return false;
          });
          

          这对我有用。 hide() 正在关闭窗口。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-02-26
            • 2019-06-21
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多