很多需要长时间在后台运行的软件,例如 QQ、微信 和很多下载工具在退出的时候默认都是最小化到系统托盘,退出需要在系统托盘菜单退出。

最小化到系统托盘相比直接最小化的优势就是在切换窗口的时候不会干扰,在任务管理器的基础页也不会显示进程。

编写系统托盘

系统托盘需要在 main 主进程中编写,如下:

const { Tray, Menu, app, BrowserWindow } = require('electron');
const path = require('path');
let tray = null;  // 用来存放系统托盘

app.on('ready', () => {
  mainWindow = new BrowserWindow({
    width: 600,
    height: 600,
    webPreferences: {
      nodeIntegration: true,
      contextIsolation: false
    }
  });

  // 创建系统托盘
  tray = new Tray(path.join(__dirname, 'img/icon.png'));
  // 菜单模板
  const menu = [
    {
      label: '全屏',
      role: 'togglefullscreen'
    },
    {
      label: '退出',
      role: 'quit'
    }
  ];
  // 给系统托盘设置菜单
  tray.setContextMenu(Menu.buildFromTemplate(menu));
  // 给托盘图标设置气球提示
  tray.setToolTip('Electron测试');
  // 加载页面文件
  mainWindow.loadFile('src/index.html');
});

系统托盘的菜单模板和 菜单栏 是差不多的,也可以设置子菜单之类的。

系统托盘需要在应用的 ready 事件中编写,但存放系统托盘的变量需要放到外面,否则系统托盘会被销毁。

使用 new Tray 创建系统托盘时至少需要传入一个图标,图标支持 pngjpg 。在程序运行的过程中也可以使用 TraysetImage 方法来更改图标。

最小化到系统托盘

Electron 的 BrowserWindow 提供了 showhide 方法,可以用来隐藏和恢复显示窗口,最小化到系统托盘就需要用到 BrowserWindowhideshow 方法。

下面实现最小化 后隐藏窗口,双击托盘图标和点击菜单可以恢复显示窗口:

const { Tray, Menu, app, BrowserWindow } = require('electron');
const path = require('path');
let tray = null;  // 用来存放系统托盘

app.on('ready', () => {
  mainWindow = new BrowserWindow({
    width: 600,
    height: 600,
    webPreferences: {
      nodeIntegration: true,
      contextIsolation: false
    }
  });

  // 创建系统托盘
  tray = new Tray(path.join(__dirname, 'img/icon.png'));
  // 菜单模板
  let menu = [
    {
      label: '显示主窗口',
      id: 'show-window',
      enabled: !mainWindow.show,
      click() {
        mainWindow.show();
      }
    },
    {
      label: '退出',
      role: 'quit'
    }
  ];
  // 构建菜单
  menu = Menu.buildFromTemplate(menu);
  // 给系统托盘设置菜单
  tray.setContextMenu(menu);
  // 给托盘图标设置气球提示
  tray.setToolTip('Electron测试');
  // 加载页面文件
  mainWindow.loadFile('src/index.html');

  // 窗口最小化
  mainWindow.on('minimize', ev => {
    // 阻止最小化
    ev.preventDefault();
    // 隐藏窗口
    mainWindow.hide();
  });

  // 托盘图标被双击
  tray.on('double-click', () => {
    // 显示窗口
    mainWindow.show();
  });

  // 窗口隐藏
  mainWindow.on('hide', () => {
    // 启用菜单的显示主窗口项
    menu.getMenuItemById('show-window').enabled = true;
    // 重新设置系统托盘菜单
    tray.setContextMenu(menu);
  });

  // 窗口显示
  mainWindow.on('show', () => {
    // 禁用显示主窗口项
    menu.getMenuItemById('show-window').enabled = false;
    // 重新设置系统托盘菜单
    tray.setContextMenu(menu);
  });
});

上面实现了点击最小化后隐藏窗口,双击托盘图标或点击菜单的 显示主窗口 可以显示窗口,菜单的 显示主窗口 项也会根据窗口的隐藏或显示动态的启用或禁用。

下面是详细说明:

显示主窗口 的菜单项加入了 idenabledid 可以用来查找菜单项,enabled 可以设置菜单禁用或启用。菜单模板中的 enabled 是直接获取窗口状态,如果窗口的 showtrue 就禁用 显示主窗口 菜单项,否则就启用。

在窗口最小化时会触发 BrowserWindowminimize 事件,通过调用 eventpreventDefault 方法可以阻止事件的默认行为,调用 BrowserWindowhide 方法可以隐藏窗口。

窗口隐藏和显示会触发 BrowserWindowhideshow 事件,通过菜单的 getMenuItemById ID 选择器获取菜单项后可以操作菜单的 enabled 来设置禁用或启用,更改完菜单后可以使用系统托盘的 setContextMenu 重新设置菜单。

注意!使用最小化事件来隐藏窗口,点击任务栏的图标最小化时也会隐藏窗口,不会最小化到任务栏。如果要实现不影响原本的最小化功能和点击关闭按钮隐藏窗口,可以考虑隐藏标题栏,使用 HTML 来自定义标题栏,三个窗口状态按钮也可以自定义。

更详细的系统托盘说明可以访问 https://www.electronjs.org/docs/api/tray

相关文章: