Electron.js如何minimize/closewindow到系统托盘并从托盘恢复window?

Electron.js How to minimize/close window to system tray and restore window back from tray?

我希望我的 Electron.js 应用程序驻留在系统托盘上,每当用户想做某事时,他们可以从系统托盘恢复做某事,然后 minimize/close 将其返回到系统托盘。我该怎么做?

我已经看过文档中的 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 存储库,但它在 linux 上无法正常工作。

其实我很久以前就想出来了,但是对于遇到同样问题的人来说,这是一种可以实现最小化到 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();
    } }
]);

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

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)

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

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() 正在关闭 window。

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

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;
    }
  });
});

比使用标志更好的方法,适合那些不想改变 minimize 行为的人:

通常使用 mainWindow.hide()

close 事件上隐藏 window
mainWindow.on('close', function (event) {
    event.preventDefault();
    mainWindow.hide();
});

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

来自the documentation

Force closing the window, the unload and beforeunload event won't be emitted for the web page, and close event will also not be emitted for this window, but it guarantees the closed event will be emitted.

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

我分享我的Sketch,在任务栏图标上最小化隐藏,菜单选项右击图标到restore/close。使用 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);
        });
    }
});

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

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