Electronデスクトップアプリ開発入門(2)
Electron APIデモから学ぶ実装テクニック ― ウィンドウ管理とメニュー
Electron API Demosで紹介されている、Electronアプリの実装テクニックを紹介。今回はウィンドウ管理とメニューの実装方法を基礎から説明する。
はじめに
前回はElectronのアーキテクチャと基本機能を紹介した。今回から次回と次々回は、Electronのデモアプリで紹介されている機能を使って、Electronアプリの実装のテクニックを紹介していく。今回はウィンドウ管理とメニューの実装テクニックを説明する。
APIデモアプリ
GitHub上のElectron公式アカウントで公開されているElectron API Demosというデモアプリは、前回説明した各種APIを使って具体的にどんなことができるのかを知るのに便利だ。よく使うクラスと使い方が、デモの中で解説されているため、これを見ていけばElectronのAPIで何ができるのかが効率的に理解できる。
そこで本稿では、このデモアプリの内容を順に解説していこう。なお、本稿ではデモのコードをそのまま転記するのではなく、そのままコードを実行できるように若干変更している。
まずは、GitHubからElectron API Demosのソースを取得して、デモアプリを実行する(リスト1)。
|
$ git clone https://github.com/electron/electron-api-demos
$ cd electron-api-demos/
$ npm install
$ npm start
|
git cloneコマンドでAPI Demosをローカルにクローンする。
npm installコマンドで実行に必要なモジュールをインストールする。
npm startコマンドでアプリケーションを起動する
リスト1のnpm startコマンドでデモアプリ(図1)が起動する。
デモアプリは、
- 説明
- デモがあるときは[View Demo]ボタン
- サンプルコード
で構成されている。[View Demo]ボタンをクリックすると、コードが実行されて、そのUIを操作したりできる。
【メニュー項目の一覧】は以下のようになっている。
それでは、メニューの各項目を順に見ていこう。
ウィンドウ管理(WINDOWS)
[WINDOWS]は、OSのWindowsのことではなく、アプリのウィンドウのことだ。つまりここでは、ウィンドウを作成・管理するためのサンプルが提供されている。
ウィンドウの作成と管理(Create and Manage windows)
新しいウィンドウの作成(Create a new window)
Electronのウィンドウは、BrowserWindowクラスで管理する。
●メインプロセスからのBrowserWindowクラスへのアクセス
最も基本的な方法となるが、メインプロセス(=package.jsonでmainに指定されたJavaScriptソース)では、リスト2の記述でBrowserWindowクラスを直接呼び出せる。
|
const BrowserWindow = require('electron').BrowserWindow
|
●レンダラープロセスからのBrowserWindowクラスへのアクセス
一方、レンダラープロセスでは、BrowserWindowクラスに直接アクセスできない(つまり、レンダラープロセスからは新しいウィンドウを作成できない)。そのため、remoteモジュール(日本語訳)を経由して、メインプロセスのBrowserWindowモジュールを取得する必要がある(リスト3)。なおremoteモジュールは、IPC(Inter-process Communication:プロセス間通信)呼び出しをラップして、レンダラープロセスからメインプロセスのオブジェクトを呼び出す簡単な方法を提供している。
|
const BrowserWindow = require('electron').remote.BrowserWindow
|
このようにメインプロセスを経由することで、新しいレンダラーウィンドウを表示できる。デモアプリでも、メインプロセスからではなく、ウィンドウ(レンダラープロセス)から別のウィンドウを作成しているため、remoteモジュールを経由してメインプロセスのBrowserWindowモジュールにアクセスしている。
●メインプロセスからウィンドウを表示する基本コード
デモのコードとは少し違うが、メインプロセスからウィンドウを表示する最も基本的なコードを紹介する(リスト4)。
|
const path = require('path')
const electron = require('electron')
const BrowserWindow = electron.BrowserWindow
const app = electron.app
app.on('ready', function() {
mainWindow = new BrowserWindow({ width: 300, height: 200 });
mainWindow.loadURL(`file://${__dirname}/index.html`);
mainWindow.on('closed', () => {
mainWindow = null;
});
});
|
先頭に必要なモジュールを宣言している。
appモジュールのreadyイベントで、ウィンドウ(BrowserWindow)を作成して、表示している。
今後、メインプロセスが「ウィンドウの表示のみ」の場合は、このコードを利用してほしい。
appモジュールのreadyイベント*1は、Electronの初期化が完了したときに発生する。Electronの処理は、ready後に記述する必要がある。
BrowserWindowクラスのコンストラクターでウィンドウサイズを指定して、loadURLメソッドで読み込むHTMLファイルを指定するとウィンドウが表示される。
- *1
appオブジェクトのイベントについては「Electron Documentation / API / app / Events」(英語)を参照してほしい。
●レンダラープロセスからウィンドウを表示する基本コード
これについては、次に説明するリスト5~7のコードを参考にしてほしい。
ウィンドウ状態の管理とフォーカス(Manage window state / Window events: blur and focus)
ウィンドウの状態管理とフォーカスは、どちらもウィンドウのイベントを処理しているデモなので、一緒に解説する。
ここでは、デモを参考に以下のファイル群を作成することにした。
- index.js: メインプロセスにおける処理。前掲のリスト4
- index.html: 親ウィンドウのHTMLソース。レンダラープロセス。以下のリスト5に掲載
- childwindow.html: 子ウィンドウのHTMLソース。レンダラープロセス。以下のリスト6に掲載
- renderer-process.js: 親ウィンドウ(レンダラープロセス)における処理。以下のリスト7に掲載
|
<html>
<style>
.smooth-appear {
opacity: 1;
transition: opacity .5s ease-in-out;
}
.disappear {
opacity: 0;
}
</style>
<body>
<button id="manage-window">Open New Window</button>
<div id="manage-window-reply"></div>
<button id="focus-on-modal-window" class="disappear">Focus</button>
<script>
// renderer-process.jsファイル(リスト7)をモジュールとして読み込む
require('./renderer-process')
</script>
</body>
<html>
|
|
<style>
body {
padding: 10px;
font-family: system, -apple-system, '.SFNSText-Regular', 'SF UI Text', 'Lucida Grande', 'Segoe UI', Ubuntu, Cantarell, sans-serif;
color: #fff;
background-color: #8aba87;
text-align: center;
font-size: 34px;
}
#close {
color: white;
opacity: 0.7;
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
font-size: 12px;
text-decoration: none;
}
</style>
<p>Click on the parent window to see how the "focus on demo" button appears.</p>
<a id="close" href="javascript:window.close()">Close this Window</a>
|
|
const BrowserWindow = require('electron').remote.BrowserWindow
const path = require('path')
const manageWindowBtn = document.getElementById('manage-window')
let win
// ボタンクリック時に、レンダラープロセスから別ウィンドウを表示
manageWindowBtn.addEventListener('click', function(event) {
const modalPath = path.join('file://', __dirname, '/childwindow.html')
win = new BrowserWindow({
width: 400,
height: 275
})
win.on('resize', updateReply)
win.on('move', updateReply)
win.on('focus', hideFocusBtn)
win.on('blur', showFocusBtn)
win.on('close', function() {
hideFocusBtn()
win = null
})
win.loadURL(modalPath)
win.show()
function updateReply() {
const manageWindowReply = document.getElementById('manage-window-reply')
const message = `Size: ${win.getSize()} Position: ${win.getPosition()}`
manageWindowReply.innerText = message
}
const focusModalBtn = document.getElementById('focus-on-modal-window')
function showFocusBtn(btn) {
if (!win) return
focusModalBtn.classList.add('smooth-appear')
focusModalBtn.classList.remove('disappear')
focusModalBtn.addEventListener('click', function() {
win.focus()
})
}
function hideFocusBtn() {
focusModalBtn.classList.add('disappear')
focusModalBtn.classList.remove('smooth-appear')
}
})
|
ウィンドウのサイズ変更(resize)、移動(move)、フォーカス(focus)、フォーカスが外れる(blur)が処理されている。
特に難しいところはないと思うが、念のため、上記のコードを理解するためのポイントを確認しておこう。
|
win.on('resize', updateReply)
win.on('move', updateReply)
function updateReply() {
const manageWindowReply = document.getElementById('manage-window-reply')
const message = `Size: ${win.getSize()} Position: ${win.getPosition()}`
manageWindowReply.innerText = message
}
|
リスト8を見ると、ウィンドウのサイズ変更(resizeイベント*2)、または移動(moveイベント*2)が発生すると、updateReply関数が呼び出されるようになっている。updateReplay関数では、ウィンドウのサイズと位置を取得して、ページ上にテキスト表示している。
- *2
BrowserWindowオブジェクトのイベントについては「Electron Documentation / API / BrowserWindow / Instance Events」(英語)を参照してほしい。
フレームなしウィンドウ(Create a frameless window)
タイトルバーやコマンドボタンなどのフレームなしウィンドウを作成するには、BrowserWindowのコンストラクターでframeにfalseを指定する。
|
const path = require('path')
const electron = require('electron')
const BrowserWindow = electron.BrowserWindow
const app = electron.app
app.on('ready', function() {
mainWindow = new BrowserWindow({ frame: false });
mainWindow.loadURL(`file://${__dirname}/index.html`);
mainWindow.on('closed', () => {
mainWindow = null;
});
});
|
BrowserWindowクラスのコンストラクターでframe: falseを指定することでフレームなしのウィンドウを表示する。
HTMLソースには特に処理を記述していないため、省略する。このコードを実行すると、タイトルバーもコントロールボタンもないウィンドウが表示される(図2)。
ウィンドウのオプションとしてフレームだけでなく、表示位置やサイズなどさまざまなオプションが指定できる。詳細はBrowserWindowのAPIリファレンスを参照してほしい。
ハングとクラッシュ(Handling window crashes and hangs)
レンダラープロセスがハングしたり、クラッシュしたりしたときに、メインプロセスから検出できる。ハング時とクラッシュ時のイベントハンドラーを記述したコードを見ていこう。
|
const {app, BrowserWindow} = require('electron');
const dialog = require('electron').dialog
const path = require('path')
app.on('ready', function() {
const hangWinPath = path.join('file://', __dirname, 'index.html')
let win = new BrowserWindow({ width: 400, height: 320 })
win.on('unresponsive', function () {
const options = {
type: 'info',
title: 'レンダラープロセスがハングしています',
message: 'このプロセスはハングしています。コマンド?',
buttons: ['再読み込み', '閉じる']
}
dialog.showMessageBox(options, function (index) {
if (index === 0) win.reload()
else win.close()
})
})
win.webContents.on('crashed', function () {
const options = {
type: 'info',
title: 'レンダラープロセスがクラッシュしました',
message: 'このプロセスはクラッシュしました。コマンド?',
buttons: ['再読込', '閉じる']
}
dialog.showMessageBox(options, function (index) {
if (index === 0) win.reload()
else win.close()
})
})
win.on('close', function () { win = null })
win.loadURL(hangWinPath)
win.show()
})
|
ウィンドウ(レンダラープロセス)がハングしたときのunresponsiveイベントと、クラッシュ時のcrashedイベント*3の、イベントハンドラーが記述されている。
- *3
unresponsiveイベントはappオブジェクトに含まれているが、crashedイベントは、webContentsプロパティにより取得できるwebContentsオブジェクト(=Webページを描画・制御するためのもの)に含まれている。webContentsオブジェクトのイベントについては「Electron Documentation / API / webContents / Instance Events」(英語)を参照してほしい。
デモアプリでは、レンダラープロセスからさらにウィンドウを表示しているため、remoteモジュールを経由してウィンドウを作成しているが、リスト10ではメインプロセスから呼び出すため、直接、ウィンドウを表示している。
ウィンドウがハング状態になるとunresponsiveイベントが発生するため、win.on('unresponsive')をハンドルして、クラッシュ時の処理を記述している(リスト11)。
|
win.on('unresponsive', function () {
const options = {
type: 'info',
title: 'レンダラープロセスがハングしています',
message: 'このプロセスはハングしています。コマンド?',
buttons: ['再読み込み', '閉じる']
}
dialog.showMessageBox(options, function (index) {
if (index === 0) win.reload()
else win.close()
})
})
|
optionsに、「メッセージダイアログのタイトル」と「メッセージ」、「表示するボタンの文字列」を設定して、dialog.showMessageBoxメソッドでダイアログを表示している。コールバック関数に、クリックされたボタンのindexが返されるため(※インデックス番号は0スタートで、[再読み込み]ボタン=0、[閉じる]ボタン=1になる)、[再読み込み]ボタンがクリックされたら(つまりindex === 0のとき)、win.reload()でウィンドウを再読み込みしている。
このように、ハング状態をunresponsiveイベントとして検出して、ウィンドウの再読み込みやアプリの終了などの対応が可能だ。
また同様に、クラッシュ時はcrashedイベントで検出できるため、同じ方法で処理を記述している。
レンダラープロセス(index.html)側では、リンクがクリックされたら、プロセスをクラッシュあるいはハングさせている。
|
<!DOCTYPE html>
<html>
<head>
<style>
body {
padding: 14px;
font-family: system, -apple-system, '.SFNSText-Regular', 'SF UI Text', 'Lucida Grande', 'Segoe UI', Ubuntu, Cantarell, sans-serif;
color: #fff;
background-color: #8aba87;
text-align: center;
font-size: 40px;
}
#crash, #hang {
color: white;
left: 50%;
text-decoration: none;
}
</style>
<title>Hello Electron</title>
<meta charset="UTF-8">
</head>
<body>
<p><a id="crash" href="javascript:process.crash()">クラッシュ</a></p>
<p><a id="hang" href="javascript:process.hang()">ハング</a></p>
</body>
</html>
|
プログラムを起動して[ハング]リンクをクリックした後、しばらく(30秒ほど)待つとダイアログが表示される(図3)。[再読み込み]ボタンをクリックすると、ウィンドウが再読み込みされる。
同じように[クラッシュ]リンクをクリックすると、プロセスがクラッシュして、ダイアログが表示される(図4)。
このようにレンダラープロセスのハングやクラッシュを検出することで、アプリが落ちてしまうような致命的な問題に対して適切な処理を記述できる。
メニュー(MENUS)
メニューのデモとしては、アプリケーションメニュー(=メニューバー)とコンテキストメニューの2つが紹介されている。
アプリケーションメニュー(Create an application menu)
このデモでは、メニューバーにカスタム項目を追加するコード(リスト13)が紹介されている。
|
const electron = require('electron')
const path = require('path')
const BrowserWindow = electron.BrowserWindow
const Menu = electron.Menu
const app = electron.app
let template = [{
label: '編集',
submenu: [{
label: 'やり直し',
accelerator: 'Shift+CmdOrCtrl+Z',
role: 'redo'
}, {
type: 'separator'
}, {
label: 'コピー',
accelerator: 'CmdOrCtrl+C',
role: 'copy'
}]
}, {
label: '表示',
submenu: [{
label: '全画面表示切り替える',
accelerator: (function() {
if (process.platform === 'darwin') {
return 'Ctrl+Command+F'
} else {
return 'F11'
}
})(),
click: function(item, focusedWindow) {
if (focusedWindow) {
focusedWindow.setFullScreen(!focusedWindow.isFullScreen())
}
}
}]
}]
if (process.platform === 'darwin') {
const name = electron.app.getName()
template.unshift({
label: name,
submenu: [{
label: `About ${name}`,
role: 'about'
}, {
label: 'Quit',
accelerator: 'Command+Q',
click: function() {
app.quit()
}
}]
})
}
app.on('ready', function() {
const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)
const winPath = path.join('file://', __dirname, 'index.html')
let win = new BrowserWindow({ width: 400, height: 320 })
win.on('close', function() { win = null })
win.loadURL(winPath)
win.show()
})
|
コードの内容は後述する。
デモアプリはメニュー項目の数が多いので、リスト13ではある程度省略した。このコードを実行すると、ウィンドウに対するメニューが表示される(図5)。


上: Windowsでは、メニューバーが表示される。
中: macOSでは、アプリケーションメニューが追加される。
下: Linux(Ubuntu)では、メニューバーが表示される。
では、リスト13のコードをブロックごとに見ていこう。
まずtemplateという変数(=テンプレート)にメニューの定義を記述している(リスト14)。
|
let template = [{
label: '編集',
submenu: [{
label: 'やり直し',
accelerator: 'Shift+CmdOrCtrl+Z',
role: 'redo'
}, {
type: 'separator'
}, {
label: 'コピー',
accelerator: 'CmdOrCtrl+C',
role: 'copy'
}]
}]
|
そのテンプレートからメニュー(=Menuオブジェクト)を構築するわけだが、そのメニューを構成する各メニュー項目を表すMenuItemオブジェクトには、以下のプロパティを設定できる。全ての項目がOptional(省略可能)になっており、何も設定しなくても(もちろん何もしない項目になるが)項目を表示できる。
| プロパティ | 説明 |
|---|---|
| label | メニューに表示するラベルを指定する。指定がない場合、ロール(後述)のデフォルト文字列を表示するか、何も表示しない |
| sublabel | WindowsとLinux環境でメニュー項目の下に説明文を表示する |
| type | メニューに表示する項目の種類を指定する。
|
| role | ロール(=項目のアクション)を設定する。設定されているときにはclickプロパティは無視される。設定可能な値は後述する |
| accelerator | メニューのショートカットキーを設定する(例:CommandOrControl+C、または省略形のCmdOrCtrl+C)。コマンドキーとしては以下が指定可能だが、macOS/Windows/Linuxで利用できるように、基本的にCmdOrCtrlの使用をお勧めする。
|
| icon | メニュー横に表示するアイコン画像を指定する。サイズが指定できないので、大きくない画像を用意する必要がある |
| enabled | メニュー項目の有効(true)または無効(false)を指定する |
| visible | メニュー項目の表示(true)または非表示(false)を指定する |
| checked | typeプロパティにcheckboxまたはradioを指定したときに、チェックされている状態(true)か、チェックされていない状態(false)かを指定する |
| submenu | 下階層のメニューを定義する |
| id | メニューを識別するIDを文字列で指定する |
| position | メニューの表示位置を指定する。idプロパティで指定された項目の挿入位置を指定する(例:'before=id-string')。詳細後述。
|
| click | メニューがクリックされたときに実行されるfunctionを記述する |
ロール(role)
roleとして指定可能な値は以下である。
| 値 | 説明 |
|---|---|
| undo | やり直し |
| redo | 繰り返し |
| cut | 切り取り |
| copy | コピー |
| paste | 貼り付け |
| pasteandmatchstyle | 元のスタイルを保持して貼り付け |
| selectall | 全て選択 |
| delete | 削除 |
| minimize | 最小化 |
| close | ウィンドウを閉じる |
| quit | アプリを終了 |
| reload | 再読み込み |
| toggledevtools | 開発者ツール(DevTools)の表示/非表示 |
| togglefullscreen | 全画面表示の切り替え |
| resetzoom | ズームのリセット |
| zoomin | 拡大 |
| zoomout | 縮小 |
以下の値はmacOSのみで利用可能なroleである。
| 値 | 説明 |
|---|---|
| about | アプリについて |
| hide | 非表示 |
| hideothers | 他を非表示 |
| unhide | 再表示 |
| startspeaking | 読み上げ開始 |
| stopspeaking | 読み上げ停止 |
| front | 全面に切り替え |
| zoom | ウィンドウを全画面表示 |
| window | サブメニューのウィンドウ |
| help | サブメニューのヘルプ |
| services | サブメニューのサービス |
メニュー項目では、前掲のリスト14のようにロールでOS標準の機能を利用することもできるし、下記のリスト15のようにclickイベントにコードを記述するなどしたカスタム処理の実装も可能だ。
|
let template = [{
label: '全画面表示切り替える',
accelerator: (function() {
if (process.platform === 'darwin') {
return 'Ctrl+Command+F'
} else {
return 'F11'
}
})(),
click: function(item, focusedWindow) {
if (focusedWindow) {
focusedWindow.setFullScreen(!focusedWindow.isFullScreen())
}
}]
}]
|
メニューの項目定義も実装もJavaScriptだけでできることがお分かりいただけただろう。
ポジション(position)
メニューの表示位置としてpositionプロパティを指定できることを表1に示したが、少し分かりにくいので、コードと実行例を示しておこう。positionプロパティにendofを記述すると、値ごとに論理グループが形成されて、記載した順に並べられて表示される。例えばリスト16では、edit/window/helpの3つの論理グループを記述している。
|
let template = [{
label: '編集',
submenu: [
{ label: 'コピー', position: 'endof=edit' },
{ label: '並べる', position: 'endof=window' },
{ label: 'アプリについて', position: 'endof=help' },
{ label: '更新', position: 'endof=help' },
{ label: '貼り付け', position: 'endof=edit' },
{ label: '選択', position: 'endof=edit' }
]
}]
|
positionプロパティにendofで論理グループを指定している。
このコードの実行結果を見てみよう。


コンテキストメニュー(Create a context menu)
アプリのウィンドウを右クリックして表示されるコンテキストメニューも、アプリケーションメニューと同じくMenuクラスで作成できる(リスト17)。
|
const electron = require('electron')
const BrowserWindow = electron.BrowserWindow
const Menu = electron.Menu
const MenuItem = electron.MenuItem
const app = electron.app
const menu = new Menu()
menu.append(new MenuItem({ label: 'Hello' }))
menu.append(new MenuItem({ type: 'separator' }))
menu.append(new MenuItem({ label: 'Electron', type: 'checkbox', checked: true }))
app.on('browser-window-created', function(event, win) {
win.webContents.on('context-menu', function(e, params) {
menu.popup(win, params.x, params.y)
})
})
app.on('ready', function() {
mainWindow = new BrowserWindow({ width: 400, height: 300 });
mainWindow.loadURL(`file://${__dirname}/index.html`);
mainWindow.on('closed', () => {
mainWindow = null;
});
});
|
MenuクラスのインスタンスにappendメソッドでMenuItemオブジェクトを追加する。
appオブジェクトのbrowser-window-createdイベントが発行されたタイミングで(つまりウィンドウが作成されたとき)、コンテキストメニュー(=webContentsオブジェクトのcontext-menuイベント)を登録している。
開いたウィンドウのcontext-menuイベントが発生したタイミングで、menu.popupメソッドを呼び出して、コンテキストメニューをポップアップ表示している。
レンダラープロセス(index.html)側の処理は、リスト18のようにしよう。
|
<html>
<body>
Context Menu
</body>
</html>
|
これを実行して、ウィンドウで右クリックするとコンテキストメニューが表示される(図7)。
コンテキストメニューなので、状態(=コンテキスト)に応じて表示内容を切り替えたい場合は、IPCで送信されたレンダラープロセス内からのメッセージを、メインプロセスのipcMainモジュールでチャネルごとに受信して、各チャネルに応じたメニューをポップアップさせるとよい(※IPCについては次回詳しく説明する)。
メインプロセスでは具体的に、show-context-menu1/show-context-menu1という2つのチャネル(=イベント名)を定義して、それぞれのイベントハンドラー内で異なるコンテキストメニューを表示する(リスト19)。
|
const electron = require('electron')
const BrowserWindow = electron.BrowserWindow
const Menu = electron.Menu
const MenuItem = electron.MenuItem
const app = electron.app
const ipc = electron.ipcMain
ipc.on('show-context-menu1', function(event) {
const menu1 = new Menu()
menu1.append(new MenuItem({ label: 'Context Menu 1' }))
const win = BrowserWindow.fromWebContents(event.sender)
menu1.popup(win)
})
ipc.on('show-context-menu2', function(event) {
const menu2 = new Menu()
menu2.append(new MenuItem({ label: 'Context Menu 2' }))
const win = BrowserWindow.fromWebContents(event.sender)
menu2.popup(win)
})
app.on('ready', function() {
mainWindow = new BrowserWindow({ width: 400, height: 300 });
mainWindow.loadURL(`file://${__dirname}/index.html`);
mainWindow.on('closed', () => {
mainWindow = null;
});
});
|
レンダラープロセスでは、状態に応じたチャネル(=先ほど定義したshow-context-menu1/show-context-menu1)にIPC(=ipcRendererモジュール)でメッセージ送信するように記述する(リスト20)。
|
<html>
<body>
<button id="context-button1">Button1</button>
<button id="context-button2">Button2</button>
</body>
<script>
const ipc = require('electron').ipcRenderer
const contextMenuBtn1 = document.getElementById('context-button1')
contextMenuBtn1.addEventListener('click', function() {
ipc.send('show-context-menu1')
})
const contextMenuBtn2 = document.getElementById('context-button2')
contextMenuBtn2.addEventListener('click', function() {
ipc.send('show-context-menu2')
})
</script>
</html>
|
ここではボタンのクリックイベントで送信するチャネルを切り替えている。
このように状態によってIPCチャネルを切り替えることで、コンテキストメニューを切り替えている。
グローバルショートカット(Register keyboard shortcuts)
グローバルショートカットは、アプリがアクティブでない状態でも利用できるショートカットキーである。さっそくコードを見てみよう。
|
const electron = require('electron')
const app = electron.app
const dialog = electron.dialog
const globalShortcut = electron.globalShortcut
app.on('ready', function() {
globalShortcut.register('CommandOrControl+Alt+K', function() {
dialog.showMessageBox({
type: 'info',
message: 'Success!',
detail: 'You pressed the registered global shortcut keybinding.',
buttons: ['OK']
})
})
})
app.on('will-quit', function() {
globalShortcut.unregisterAll()
})
|
globalShortcut.registerメソッドで、ショートカットキーを登録している。
このサンプルは、UIを持たないアプリのため、HTMLソースはない。アプリ起動時(=readyイベント)にglobalShortcut.registerメソッドを使って、Command/Contrl+Alt+Kキーを同時に押すとメッセージボックスを表示するショートカットキーを登録している。また、アプリの終了時(=will-quitイベント)で globalShortcut.unregisterAllメソッドを呼び出して、登録したショートカットキーを解除している。
アプリを起動してもウィンドウが表示されないため、アプリがアクティブになることはない。何がアクティブになっていてもよいので、登録したショートカットキーを押してみると、メッセージボックスが表示される(図8)。

システム全体で使うようなアプリに使うとよいだろう。
まとめ
今回は、Electron API Demosのウィンドウ管理機能とメニューについて解説した。次回は、OSのネイティブ機能の呼び出しや、IPCを使ったアプリ内のプロセス間通信を解説する。
1. Electronとは? アーキテクチャ/API/インストール方法/初期設定
Windows/macOS/Linuxで実行できるデスクトップアプリをWeb技術で作ろう! Electronの概要から開発を始めて動かすところまでを解説する。
2. 【現在、表示中】≫ Electron APIデモから学ぶ実装テクニック ― ウィンドウ管理とメニュー
Electron API Demosで紹介されている、Electronアプリの実装テクニックを紹介。今回はウィンドウ管理とメニューの実装方法を基礎から説明する。
3. Electron APIデモから学ぶ実装テクニック ― ネイティブUIと通信
Electron API Demosで紹介されている、Electronアプリの実装テクニックを紹介。今回はネイティブUIと通信の実装方法を基礎から説明する。
4. Electron APIデモから学ぶ実装テクニック ― システムとメディア
Electron API Demosで紹介されている、Electronアプリの実装テクニックを紹介。今回はシステムとメディアの実装方法を基礎から説明する。