Electron.js如何最小化/关闭窗口到系统托盘并从托盘恢复窗口?

时间:2016-06-15 07:27:13

标签: javascript node.js electron nw.js

我希望我的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上无法正常工作。

7 个答案:

答案 0 :(得分:62)

我实际上很久以前就已经弄明白了,但对于那些遇到同样问题的人来说,有一种方法可以实现最小化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();
    } }
]);

答案 1 :(得分:8)

如果您希望一直显示系统托盘上的图标,直到您不退出应用程序,我就会使用方案更新代码

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)

答案 2 :(得分:4)

上述答案的补充-isQuiting标志也值得在应用程序的before-quit回调中设置。这样,如果操作系统或用户以其他方式(例如,通过Macos Dock任务栏的quit命令。完整的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;
    }
  });
});

答案 3 :(得分:0)

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

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

答案 4 :(得分:0)

一种比使用标志更好的方式,对于那些不想更改minimize行为的人而言:

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

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

答案 5 :(得分:0)

我分享我的 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 :(得分:0)

这是用 NW.js 标记的,因为所有其他答案都是针对 Electron 的,所以我想我想展示一下 NW.js 中的一切总是容易得多。此处设置了一个简单的演示存储库:

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