Electronアプリのカスタムメニューの設定

記事
IT・テクノロジー

Electronアプリのカスタムメニューの設定

Electron フレームワークを使って、デスクトップアプリを作る方法についてお届けしています。 前回までに、基本的な Electron アプリの作成方法を、シンプルな方法から、Vue/React などのフレームワークを利用して作るやり方や、Windows/Mac/Linux 向けの配布パッケージを作る方法をお届けしてきました。

今回は、カスタムでメニューを作るやり方について解説します。

何も設定しないと標準設定のメニュが自動で設定されます。

これまで紹介した Electron のアプリは、シンプルなもので特にメニューの設定はしていません。 何も設定しないと、File/Edit/View/Window/Help のメニューがメインウインドウに挿入されます。

しかし、実際にアプリを開発する場合、メニューの内容や処理方法が違うのでカスタマイズしたい部分です。

ここでは、メインウインドウのメニューバーのカスタマイズを例にそのやり方を説明して行きます!

シンプルなアプリの場合、エントリーポイントになるコードでメニューの設定をします。 まずは、メニューのテンプレートを作ります。簡単のためにファイル(File)メニューの下に、アプリを終了する「Quit」だけを入れることにします。

const menuTemplate: Menu = Menu.buildFromTemplate([
  {
    label: "File",
    submenu: [
      {
        label: "Quit",
        accelerator: "Control+Q",
        click() {
          app.quit();
        },
      },
    ],
  },
]);
例では、キーボードショートカットに「コントロール +  Q」でウインドウを終了するようになっています。

あとは、メインウインドウを作るときにこのメニューをセットすればカスタムのメニューがメインウインドウにセットされます。

function createWindow() {
  mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: true,
    },
  });
  Menu.setApplicationMenu(menuTemplate);
  mainWindow.loadFile(`index.html`);
}
これだけです。

Mac の場合は注意が必要!

メニューを入れるだけならば簡単です。 しかし、Mac 向けのアプリの場合は注意が必要です。 実は、Mac の場合は挙動が少し他の OS と違います。 Mac 用の配布パッケージを作るには、Mac 上でサインをする必要があるので基本的に Mac を持っているのが前提です。その場合は試せばわかることですが、Mac の場合、全てのアプリでメニューバーがアプリのウインドウではなく、ディスプレーの上に表示されるようになっています。これは、アプリによらず全てのアプリで同じ操作性を提供するために、アップルが標準的なメニューのガイドラインを作っているためです。

マックの場合の違いは、以下の2点が大きな違いです。

最初のメニュがアプリ名
最初のメニューはアプリ名が表示される(標準設定では「Electron」)が表示されます。このため、テンプレートで最初に設定したメニューのラベルで指定した文字が表示されません(上の例では「File」)

サブメニューを指定しないと表示されない
もう一つの大きな違いが「サブメニュー(submenu)」を指定しないとメニューバーに表示されません。 これは、Linux や Windows の場合、メニューバーにサブメニューなしのメニューを設定して、クリックしたときに実行するような実装が可能ですが、Mac の場合には、サブメニューがないメニューは無視されて表示されません。これは、必ずサブメニューを実装して使うというアプリのガイドラインの制約によるもののようです。

ということで、共通のソースコードで Mac もサポートする場合は、Mac の場合は別に記述をする必要があります。シンプルな例で Mac とそれ以外(Windows/Linux)で別のメニューのテンプレートを定義する方法を紹介しておきます。

import { app, BrowserWindow, Menu } from "electron";
let mainWindow: BrowserWindow | null = null;
const isMac: boolean = process.platform === "darwin";
const menuTemplate: Menu = Menu.buildFromTemplate(
  isMac
    ? // For Mac
      [
        // Dummy label for Mac menu bar
        {
          label: "",
        },
        {
          label: "File",
          submenu: [
            {
              label: "Quit",
              accelerator: "Command+Q",
              click() {
                app.quit();
              },
            },
          ],
        },
      ]
    : // Others -- Windows / Linux
      [
        {
          label: "File",
          submenu: [
            {
              label: "Quit",
              accelerator: "Control+Q",
              click() {
                app.quit();
              },
            },
          ],
        },
        {
          label: "Edit",
        },
      ]
);

function createWindow() {
  mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: true,
    },
  });
  mainWindow.webContents.openDevTools();
  Menu.setApplicationMenu(menuTemplate);
  mainWindow.loadFile(`index.html`);
}
app.whenReady().then(createWindow);
// Quits this application when all windows are closed.
app.on("window-all-closed", () => {
  app.quit();
  mainWindow = null;
});
その他の違いですが、キーボードショートカットは、Mac の場合は「コマンドキー」を利用するのが慣例なので、Windows/Linux とは別のショートカットを定義しています。

* Mac アプリの終了  Command + Q
* Windows / Linux アプリの終了  Control + Q
あとは、最後の記述ですが、Window が閉じられた場合、アプリを終了するようにしています。 これは、Mac の場合ウインドウを閉じただけだと、Deck にアプリのアイコンが残ってしまうのを防ぐためです。

ちょっとした違いですが、共通のソースコードを使って、複数のプラットフォーム向けにアプリを作るには、プラットフォームごとの制約をよく理解して、それに対応したコードを各必要があります。

実際は、Mac の場合、Mac がないと基本的に配布パッケージの生成がエラーになりますが、リリース前にテストをすることを考えると、全てのプラットフォームでの動作環境が必要ということになります。

まとめ
今回は、Electron のデスクトップアプリのメニューをカスタマイズする方法を紹介しました。 設定自体は簡単ですが、プラットフォームごとに微妙な違いがあります。

Electron を使えば、同じソースコードで Windows/Mac/Linux のデスクトップアプリの開発が可能ですが、全てのプラットフォームをサポートするには、各プラットフォームの制約などを理解してきちんとテストを行うことが重要です。

特に、Mac の場合、メニューの挙動は、Windows/Linux とは少し異なりますので注意が必要です。
サービス数40万件のスキルマーケット、あなたにぴったりのサービスを探す