SourceChord

C#とXAML好きなプログラマの備忘録。最近はWPF系の話題が中心です。

Electronで各種ダイアログ表示

今度はElectronのdialogモジュールを使い、いろいろなダイアログ表示をしてみます。

↓のドキュメントを参考にやってみます。
http://electron.atom.io/docs/v0.34.0/api/dialog/

dialogモジュールを使うと、メッセージボックスの表示や、ファイルを開く、ファイルを保存、などのダイアログ表示ができます。
このモジュールでは以下のようなメソッドが用意されています。

dialog.showOpenDialog([browserWindow][, options][, callback])
dialog.showSaveDialog([browserWindow][, options][, callback])
dialog.showMessageBox([browserWindow][, options][, callback])
dialog.showErrorBox(title, content)

このうち、shorErrorBox以外の3つは、若干の違いはありますが呼び出し方は似た感じ。
メソッドの引数には以下のようなものを渡します。

  • browserWindow: ダイアログの親となるウィンドウ
  • options: オプション
  • callback: コールバック関数

もう一個の、showErrorBoxは、ダイアログに表示するタイトルと本文を設定するだけのシンプルなものです。

てことで、順番にこれらの使い方を見ていきます。

ファイル操作系のダイアログ

まずはファイル系のダイアログ。
これらのメソッドでは、実行環境のOSに応じたダイアログ表示をしてくれます。
こういうos標準のダイアログを使ったり、ファイル操作などが普通にできるってのもいいですね。

showOpenDialog・・・ファイルを開くダイアログ

saveOpenDialogというメソッドで、ファイルを開く/フォルダを開くダイアログを表示できます。
メソッドシグネチャはこんな感じ↓

dialog.showOpenDialog([browserWindow][, options][, callback])

optionsプロパティには以下のような要素を設定します。

optionsの設定内容

プロパティ名 内容
title ダイアログのタイトルを設定
defaultPath ダイアログを開いたときの初期表示状態のパスを設定
filters ファイル選択時のフィルタ設定。
properties その他いろいろ細かな設定

filterプロパティには、こんな風にファイル選択時のフィルタ設定をします。

filters: [
    { name: 'JPEG File', extensions: ['jpg', 'jpeg']},
    { name: 'TIFF File', extensions: ['tif', 'tiff']},
    { name: 'All Files', extensions: ['*'] }
]

propertiesには、以下の要素を配列で指定します。
createDirectoryの内容は、ドキュメント見ただけではちょっとわかりませんでした。。。orz

  • openFile : ファイルを選択するダイアログにする。
  • openDirectory : ディレクトリ選択ダイアログにする。
  • multiSelections : 複数選択できるようにするか設定
  • createDirectory : ・・・

こんな風に複数の項目を指定できます。

properties: ['openFile', 'multiSelections']

使い方

var win = remote.getCurrentWindow();
var options = {
    title: 'タイトル',
    filters: [
        { name: 'JPEG File', extensions: ['jpg', 'jpeg']},
        { name: 'All Files', extensions: ['*'] }
    ],
    properties: ['openFile', 'createDirectory']
};

dialog.showOpenDialog(win, options);

showSaveDialog・・・ファイルを保存ダイアログ

こちらも使い方はだいたい同じです。
ただし、こちらのoptionsプロパティにはpropertiesの設定はありません。

かんたんなコード例だけメモ。
使い方

var win = remote.getCurrentWindow();
var options = {
    title: 'タイトル',
    filters: [
        { name: 'JPEG File', extensions: ['jpg', 'jpeg']},
        { name: 'All Files', extensions: ['*'] }
    ]
};

dialog.showSaveDialog(win, options);

メッセージボックス系のダイアログ

showMessageBox・・・メッセージボックス

続いてメッセージボックス。
alertメソッドで出すようなのとは違い、いろいろと表示をカスタマイズできるので、何かと使いどころはありそうです。

プロパティ 内容
type メッセージボックスのタイプを設定する。(info, 'warning'のいずれかを文字列で指定)
buttons メッセージボックスのボタンを設定。文字列の配列として設定します。
title タイトルを設定する
message メッセージを設定
detail メッセージボックスの詳細メッセージを設定
icon ダイアログに表示するアイコン画像を設定。

こんな風に使います。

function showMessageBox() {
    var win = remote.getCurrentWindow();
    var options = {
        type: 'info',
        buttons: ['OK', 'テスト', 'Cancel', 'sample', 'Yes', 'No'],
        title: 'タイトル',
        message: 'メッセージ',
        detail: '詳細メッセージ'
    };
    
    dialog.showMessageBox(win, options);
}
buttonsプロパティについて

buttonsプロパティは、表示するボタンの定義を文字列の配列として定義します。

この時の注意として、「OK」や「Cancel」などのような文字列を設定したときの動作が特殊っぽいので注意が必要です。

自分のWindows環境で動かしてみると、
「OK」「Cancel」「Yes」「No」の文字列を指定した場合は、ダイアログ下部に並んだボタンに表示され、それ以外の文字列を指定したボタンは、ダイアログ中に並びます。

例えばこう書くと

var win = remote.getCurrentWindow();
var options = {
    type: 'info',
    buttons: ['OK', 'テスト', 'Cancel', 'sample', 'Yes', 'No'],
    title: 'タイトル',
    message: 'メッセージ',
    detail: '詳細メッセージ'
};

dialog.showMessageBox(win, options);

↓こんな風になります。
f:id:minami_SC:20151105005111p:plain

この辺のbuttonsプロパティの動作については、特にドキュメントにも書かれていないので、ちょっとよくわからん部分。。。

showErrorBox・・・エラーダイアログ

最後はエラーダイアログ。
エラーダイアログを表示するためのメソッドです。

アプリの通常の動作としてはあまり使わないかもしれませんが、覚えておくと、デバッグ用にお手軽で便利かも。
ブラウザのalertメソッドが使えない、MainProcess側でちょろっとalertの代わりに使ったりできるかも知れません。

dialog.showErrorBox("タイトル", "本文");

呼び出すとこんな感じのダイアログが表示されます。
f:id:minami_SC:20151105005144p:plain

サンプル

ボタンを押すと、これらの4種類のダイアログ表示をするサンプルです。

f:id:minami_SC:20151105005155p:plain:w350

MainProcess、RendererProcessはそれぞれこんな感じのコード。

main.ts(MainProcessのコード)

import app = require('app');
import BrowserWindow = require('browser-window');
require('crash-reporter').start();

// メインウィンドウの参照をグローバルに持っておく。
var mainWindow: GitHubElectron.BrowserWindow = null;

// すべてのウィンドウが閉じられた際の動作
app.on('window-all-closed', function() {
  // OS X では、ウィンドウを閉じても一般的にアプリ終了はしないので除外。
  if (process.platform != 'darwin') {
    app.quit();
  }
});

app.on('ready', function() {
  // 新規ウィンドウ作成
  mainWindow = new BrowserWindow({ width: 800, height: 600 });
  // index.htmlを開く
  mainWindow.loadUrl('file://' + __dirname + '/index.html');

  // ウィンドウが閉じられたら、ウィンドウへの参照を破棄する。
  mainWindow.on('closed', function() {
    mainWindow = null;
  });
});

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Hello World!</title>
    <script src="index.js"></script>
  </head>
  <body>
    <h1>Dialog Module Test</h1>
    <hr/>
    <button onclick="showOpenDialog()">Open Dialog</button>
    <button onclick="showSaveDialog()">Save Dialog</button>
    <button onclick="showMessageBox()">Message Box</button>
    <button onclick="showErrorBox()">Error Box</button>
  </body>
</html>

index.ts(RendererProcessのコード)

var remote = require('remote');
var dialog = remote.require('dialog');

function showOpenDialog() {
    var win = remote.getCurrentWindow();
    var options = {
        title: 'タイトル',
        filters: [
            { name: 'JPEG File', extensions: ['jpg', 'jpeg']},
            { name: 'All Files', extensions: ['*'] }
        ],
        properties: ['openFile', 'createDirectory']
    };
    
    dialog.showOpenDialog(win, options);
}

function showSaveDialog() {
    var win = remote.getCurrentWindow();
    var options = {
        title: 'タイトル',
        filters: [
            { name: 'JPEG File', extensions: ['jpg', 'jpeg']},
            { name: 'All Files', extensions: ['*'] }
        ]
    };
    
    dialog.showSaveDialog(win, options);
}

function showMessageBox() {
    var win = remote.getCurrentWindow();
    var options = {
        type: 'info',
        buttons: ['OK', 'テスト', 'Cancel', 'sample', 'Yes', 'No'],
        title: 'タイトル',
        message: 'メッセージ',
        detail: '詳細メッセージ'
    };
    
    dialog.showMessageBox(win, options);
}

function showErrorBox() {
    dialog.showErrorBox("タイトル", "本文");
}

同期/非同期呼び出しの切り替え

これらのダイアログボックス系のメソッドは、コールバックが設定されていない場合は同期的な呼び出し、コールバック関数が設定された場合は非同期処理をします。

同期的な呼び出し

同期的に呼び出す場合は、ダイアログの実行結果をメソッドの戻り値として取得できます。

var result = dialog.showOpenDialog(win, options);
alert(result);
非同期な呼び出し

非同期に呼び出す場合は、コールバック関数の引数にダイアログの実行結果が渡ってきます。

dialog.showOpenDialog(win, options, (ret) => {
    alert(ret);
});