24
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Electron で Tray を使う(macOS, Windows)

Last updated at Posted at 2020-10-03

Electron の Tray クラスについては公式ドキュメントにも、Apple や Microsoft の公式ドキュメントにも詳細が載っていないので、悩む部分が多かったです。そこで、自分で実際に調べ、得たものも含めて、ここに書いてシェアしようと思います。

サンプルアプリケーション

これらの Tray を理解する手助けとして、サンプルアプリケーションを用意しました。シンプルな3分間タイマーで、その残り時間をパーセントに変換して、Tray にアイコン表示するというものです。これ以降、コードを記載するときは、ここにアップロードしてある実際のソースコードから抜粋しています。

SimpleTimer - GitHub
https://github.com/hibara/SimpleTimer
SnapCrab_SimpleTimer_2020-10-4_17-16-16_No-00.png
レポジトリには、「node_modules」が含まれておりませんので、ビルドする場合はローカルに pull した後に、当ディレクトリで npm install コマンドを実行してから行ってください。

実際の動作を見たい場合は、アプリケーションをビルドしておきました。ダウンロードしてお試しください。
https://github.com/hibara/SimpleTimer/releases

Windows:
https://github.com/hibara/SimpleTimer/releases/download/v1.0.6/SimpleTimer-win32-ia32.zip

macOS:
https://github.com/hibara/SimpleTimer/releases/download/v1.0.6/SimpleTimer-darwin-x64.zip

Tray とは?(macOS, Windowsのそれぞれにおいて)

クラス: Tray
https://www.electronjs.org/docs/api/tray

Electronの Tray とは、macOS のデフォルトでは右上にある「メニューバー」に表示するアイコン、

macOS-menubar.png

Windows のデフォルトでは、右下にある「タスクトレイ」を指します。

Windows-tasktray.png

主な機能は、アイコンを変えることでアプリケーションの状態をコンパクトにユーザーへ伝えることと、そこに表示されるアイコンをクリックすることでコンテキストメニューを出すこともできます。

表示アイコンのサイズ

タスクバー、またはタスクトレイにアイコンを表示するには、macOS, Windows 用にそれぞれ別途用意する必要があります。

macOS の場合

タスクバー表示に必要となる分の、.png ファイルを用意します。

そのタスクバーに表示されるアイコンのサイズを知るには、実際の画面パーツを Apple 公式からダウンロードして確かめることができます。

https://developer.apple.com/design/resources/

ただ、実際 Photoshop などで開いたところで、内部でどのサイズ、解像度を用意すれば良いか分かりません。サイズ、解像度については以下にファイル規則など含め書かれていますが、肝心の「タスクバー」のアイコンサイズは見つかりません。

https://developer.apple.com/design/human-interface-guidelines/macos/icons-and-images/image-size-and-resolution/

ですので、実際にトライ&エラーで試してサイズと解像度を出してみました。私が独自調査した結果は以下の通りです。

image-size@1x.png
縦(高さ)だけは、点線部分(18px)で揃えると、他のタスクバーアイコンと揃うと思います。
image-size@2x.png
もちろん、これ以上のサイズで作成することも可能ですが、タスクバーから盛大にはみ出ます(特に高さ)。幅は、「any」という記述もあったので、横長のアイコンも表示可能でしょうが、今回は検証しません。

macOSのトレイアイコン名の規則

ここで、気になってくるのは、macOS にある独特の画像ファイルの命名規則です。

これは macOS 側が、将来的に画像解像度を上げてきたとしても、自動的に適用できるための「仕様」として機能しています。

たとえば、「100.png」というファイル名があったとして、コード内で 100.png を指定したとしても、自動的にその環境に最適な解像度のファイル、100@1x.png100@2x.png を選択してくれます。ちなみに、100@1x.png = 100.png です。どちらのファイル名でも大丈夫です。

@1x は、オリジナルサイズの解像度を指し、この画像サイズが「24 x 24px」ならば、@2x は、「48 x 48px」となり、もし @3x が存在するならば、「72 x 72px」です。

Windows の場合

Windows の場合は、macOS と異なり、.icoファイルを指定します。ただ、Windows の場合も、明確な公式ドキュメントが見つかりませんでした。

Windowsアイコンの仕様については、以下を信じることにします。
https://docs.microsoft.com/ja-jp/windows/win32/uxguide/vis-icons?redirectedfrom=MSDN#size-requirements

  • フルセット:16x16, 32x32, 48x48, 256x256
  • クラシックモード(フルセット): 16x16, 24x24, 32x32, 48x48, 64x64

どう考えてもタスクトレイに入るアイコンにしては、大きすぎる 256x256 サイズが含まれていますが、一応従っておきましょう(たぶん入っていなくても表示はされるとは思いますが・・・)。

Windows アイコンの作成方法

ネット検索していただければ、オンラインで作成する方法はたくさんあると思います。

デスクトップツールだと、icofx が、確実で使いやすく鉄板でしょうか。特に大量にアイコンファイルを処理したいときにバッチ処理が使えます。ただしシェアウェアなので、購入に躊躇される方もいるかもしれません。

png2ico というフリーの老舗コマンドラインツールもありますが、最終更新が古すぎて、Windows 7 から導入された、256pxサイズのアイコンには対応していないようです。256px以上のサイズの PNG ファイルを読み込ませようとすると、以下のようなエラーメッセージが表示されてしまいます。

Width must be multiple of 8 and <256. Height must be <256.

そこで、思い切ってアイコン生成アプリケーションを自作してみました。icofx ほどの高機能性はありませんが、最低限の .ICOファイルを作るには十分でしょう。.NET Framework 4.0 製でソースもMITライセンスで上がっています。よろしければお試しください。

Png2WinIco
https://github.com/hibara/Png2WinIco

実行ファイル:
https://github.com/hibara/Png2WinIco/releases

アイコンファイル作成に必要な、256 x 256px 以上の高解像度を持つ .PNG ファイルをドラッグ&ドロップするだけで、自動的に各サイズにリサイズ格納されたアイコンファイルを作成することができます。

実装する

実装はさして難しくありません。process.platform で、macOS か Windows かを判定して、それぞれに合ったアイコンファイルを割り当てます。

このコード例では、簡単なコンテキストメニュー(アプリケーションの終了コマンドのみ)も含めています。

main.js
// トレイアイコンを生成する
let tray = null;

const createTrayIcon = () => {
  let imgFilePath;
  if (process.platform === 'win32') { // Windows
    imgFilePath = __dirname + '/images/tray-icon/white/100.ico';
  }
  else{ // macOS
    imgFilePath = __dirname + '/images/tray-icon/black/100.png';
    // 一応、macOS のダークモードに対応しておく
    if ( nativeTheme.shouldUseDarkColors === true ){
      isDarkTheme = true;
      imgFilePath = __dirname + '/images/tray-icon/white/100.png';
    }
  }
  const contextMenu = Menu.buildFromTemplate([
    { label: '終了', role: 'quit' }
  ]);
  tray = new Tray(imgFilePath);
  tray.setToolTip(app.name);
  tray.setContextMenu(contextMenu);
}

あとは、タイマーが経過する度に残り時間を計算して、パーセンテージから5%刻みで用意されたアイコンに表示を差し替えます。ゆっくりではありますが、タスクバー(またはタスクトレイ)の円が、アニメーションして変化していくのが分かると思います。

main.js
// タイマーの表示
const displayTimer = (valMilliSeconds) => {
  mainWindow.webContents.send("ipc-display-timer", valMilliSeconds);
  // タスクトレイのアイコン表示
  let percent = Math.floor((valMilliSeconds / MAX_MILLI_SECONDS) * 100);
  // 5の倍数で丸める
  let multipleOfFive =  Math.round(percent / 5) * 5;

  let imgFilePath;
  let imgFileName = ('000' + multipleOfFive).slice(-3) + (process.platform === 'win32' ? '.ico' : '.png');
  if ( process.platform === 'win32' || isDarkTheme === true ) {
    imgFilePath = __dirname + '/images/tray-icon/white/' + imgFileName;
  }
  else {
    imgFilePath = __dirname + '/images/tray-icon/black/' + imgFileName;
  }

  tray.setImage(nativeImage.createFromPath(imgFilePath));
  tray.setToolTip(percent + "% - " + app.name);
};

macOS でリアルタイムにダークモード変更されたときにも対応しておく

アプリケーションが動作しているのが、macOS なら「ダークテーマに変更」イベントが発生しますので、それに合わせてアイコンカラーも変更するようにしておくべきでしょう。

main.js
// システムカラーの変更イベント
if ( process.platform === 'darwin' ) { 
  nativeTheme.on("updated", () => {
    isDarkTheme = nativeTheme.shouldUseDarkColors === true;
  });
}

Tray アイコンが消えてしまう問題

以下のリンクにある Electron 公式ドキュメントの FAQ にもありますが、変数のスコープによるものらしいです。グローバルではなく、ローカルで Tray を生成すると、ガベージコレクションで消えてしまうようです。

Electron FAQ | Electron
https://www.electronjs.org/docs/faq#%E6%95%B0%E5%88%86%E7%B5%8C%E3%81%A4%E3%81%A8%E3%82%A2%E3%83%97%E3%83%AA%E3%81%AE-tray-%E3%81%8C%E6%B6%88%E5%A4%B1%E3%81%97%E3%81%BE%E3%81%99%E3%80%82

前述のサンプルコードでも、関数の中にではなく、グローバルに let tray = null; と記述してあります。

ちなみに Windows のタスクトレイアイコンは「まれに」消えない

タスクトレイにアイコンを表示したアプリケーションを終了したとき、「まれに」アイコンが消えないことがあります。これは前述の問題とは関係なく、Windows の仕様です。

これは Electron の問題でもなんでもなく、私が .NET Framework や、C++Builder で Windows アプリケーションを開発していた頃にもあった仕様です。ただ、アイコンが残ってしまったとしても、アプリケーションを終了した後で、そのアイコン部分へマウスカーソルを持って行くと消えてくれます。

これって、Windows XP 以前からある問題なんですが、Microsoft は改善する気はないんですかね・・・

24
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?