マルチなウィンドウのElectronアプリで、メニュー制御する話

Electronのアプリで、ウィンドウ毎に、メニューを切り替えたいとか、
有効無効を切り替えたいことってあると思うんです。

今回はフォーカスが当たっている時だけ、メニューを有効にする方法の話。

メニューアイテムのenabledを切り替える

メニューの有効無効を切り替えるには、
メニューのアイテムのenabled属性を切り替えれば良し。


メニューを作るときに、id属性を設定しておいて。

import {Menu} from 'electron';

const menuList = [
  {
    ... (略) ...
  },
  {
    label: '辞書',
    submenu: [
      {
        id: 'dict-close', // ←←← idを設定
        enabled: false,
        label: '辞書を閉じる (⌘W)',
        click() { if (myApp.dictWindow) { myApp.dictWindow.close(); } },
      },
      {
        id: 'dict-tutorial', // ←←← idを設定
        enabled: false,
        label: '辞書チュートリアル',
        click() { if (myApp.dictWindow) { myApp.dictWindow.webContents.send('menu', 'tutorial'); } },
      },
      {type: 'separator'},
      {
        id: 'dict-add', // ←←← idを設定
        enabled: false,
        label: '定義データ追加 (⌘N)',
        click() { if (myApp.dictWindow) { myApp.dictWindow.webContents.send('menu', 'add'); } },
      },
    ]
  },
  {
    ... (略) ...
  },
];
const menuTemplate = Menu.buildFromTemplate(menuList);
Menu.setApplicationMenu(menuTemplate);

そのidでメニューを取り出して、enabled属性を切り替える。

import {Menu} from 'electron';

const dictMenuItems = [
  'dict-close',
  'dict-tutorial',
  'dict-add',
  'dict-delete',
  'dict-save',
  'dict-cancel',
  'dict-export',
  'dict-reset',
];

const menu = Menu.getApplicationMenu();
for (let m of dictMenuItems) {
  const item = menu.getMenuItemById(m);
  item.enabled = true; // ←←← enabledを切り替え
}

フォーカスされたらメニューを有効に、フォーカスが外れたらメニューを無効に

BrowserWindowがフォーカスされている時だけメニューを有効にするには、
focus、blur、それとcloseのイベントを拾う。
closeも拾って置かないと、フォーカスされた状態でウィンドウ閉じられると、
ウィンドウ閉じてるのにメニューが有効なままになる。

this.dictWindow.on('close', () => {
  disableDictMenu(); // ←←← イベントを拾って、メニューのenabledを切り替える
});
this.dictWindow.on('focus', () => {
  enableDictMenu(); // ←←← イベントを拾って、メニューのenabledを切り替える
});
this.dictWindow.on('blur', () => {
  disableDictMenu(); // ←←← イベントを拾って、メニューのenabledを切り替える
});


ウィンドウまわりのコードも含めると。

... (略) ...

function showDictWindow(): void {
  const acceptFirstMouse = this.appCfg.acceptFirstMouse;
  this.dictWindow = new BrowserWindow({
    width: width,
    height: height,
    show: false, // show at did-finish-load event
  });
  this.dictWindow.loadURL(`file://${__dirname}/contents-dict.html`);

  // window event
  this.dictWindow.webContents.on('did-finish-load', () => {
    myApp.dictWindow.show(); myApp.dictWindow.focus();
  });
  this.dictWindow.on('close', () => {
    disableDictMenu();
  });
  this.dictWindow.on('focus', () => {
    enableDictMenu();
  });
  this.dictWindow.on('blur', () => {
    disableDictMenu();
  });
}

メニューのacceleratorが邪魔な話

メニューアイテムにacceleratorを設定していると、
そのショートカットキーは、全てのウィンドウで効いてしまう。

import {Menu} from 'electron';

const menuList = [
  {
    ... (略) ...
  },
  {
    label: '辞書',
    submenu: [
      {
        role: 'quit',
        accelerator: 'Command+Q', // ←←← acceleratorってこれ
      },
    ]
  },
  {
    ... (略) ...
  },
];
const menuTemplate = Menu.buildFromTemplate(menuList);
Menu.setApplicationMenu(menuTemplate);

これが邪魔なら、なんらかの対処をいれましょう。

acceleratorを無効にするか、
有効にしたい時以外はacceleratorを切る。

終わり

オワリダヨ