Electron – チュートリアルその7 子ウィンドウを作成する方法

目次

概要

これまでのチュートリアルでは単一の画面を持つ Electron アプリでしたが、本記事では、子ウィンドウを作成するための方法を解説します。

本記事で紹介するコードは以下を参照ください。

electron-examples/07_electron-create-child-dialog

子ウィンドウを作成する

メインウィンドウでボタンをクリックしたら、子ウィンドウを開くアプリを作成します。 処理の流れとしては、次のようになります。

  1. 親ウィンドウの HTML 上でボタンをクリックすると、IPC によりメインレンダラーに子ウィンドウを開く指示を送信する
  2. メインレンダラーで子ウィンドウを開く指示を受信したら、子ウィンドウを作成する

1. プリロードスクリプトを作成する

チャンネル openDialog でメインレンダラーに子ウィンドウを開く指示を送信する openDialog() という API を用意します。

preload.ts

import { contextBridge, ipcRenderer } from "electron";

contextBridge.exposeInMainWorld("Electron", {
  // Renderer -> Main
  openDialog: (title: string) => ipcRenderer.send("openDialog", title),
});

2. メインプロセスで子ウィンドウを開く処理を作成する

ipcMain.on() でチャンネル openDialog のデータを受信した場合のコールバック関数を登録します。 この関数では、new BrowserWindow() で子子ウィンドウを作成し、child.html を読み込みます。 このとき、parent 引数に親ウィンドウを指定すると、子ウィンドウは親ウィンドウより常に前面に表示されるようになります。

main.ts

import { app, BrowserWindow, ipcMain, IpcMainEvent } from "electron";
import * as path from "path";

const createWindow = () => {
  const win = new BrowserWindow({
    webPreferences: {
      preload: path.join(__dirname, "preload.js"),
    },
  });
  win.webContents.openDevTools();
  win.loadFile("index.html");

  ipcMain.on("openDialog", (event: IpcMainEvent, title: string) => {
    const dialog = new BrowserWindow({
      parent: win,
      title: title,
    });
    dialog.webContents.openDevTools();
    dialog.loadFile("child.html");
  });
};

app.whenReady().then(createWindow);

3. 親ウィンドウと子ウィンドウの HTML ファイルを作成する

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
  </head>
  <body>
    <h1>親ウィンドウ</h1>
    <button onclick="Electron.openDialog('Child')">子ウィンドウを開く</button>
    <p id="recieve"></p>
  </body>
</html>

child.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
  </head>
  <body>
    <h1>子ウィンドウ</h1>
  </body>
</html>

重複起動を防止する

すでに子ウィンドウが開いている場合はウィンドウを開かないようにするには、次のようにします。

  1. childWin をグローバル変数にし、ウィンドウが開かれていないときは値が null となるようにする
  2. childWinnull でない場合は、すでにウィンドウが開かれているので、ウィンドウを開かない
  3. childWinclosed イベントを購読し、ウィンドウが閉じられた場合は、再び childWinnull を設定する

main.ts

import { app, BrowserWindow, ipcMain, IpcMainEvent } from "electron";
import * as path from "path";

let childWin: BrowserWindow | null = null;
const createWindow = () => {
  const win = new BrowserWindow({
    webPreferences: {
      preload: path.join(__dirname, "preload.js"),
    },
  });
  win.webContents.openDevTools();
  win.loadFile("index.html");

  ipcMain.on("openDialog", (event: IpcMainEvent, title: string) => {
    if (childWin !== null) {
      return;
    }

    childWin = new BrowserWindow({
      parent: win,
      title: title,
    });
    childWin.webContents.openDevTools();
    childWin.loadFile("child.html");

    childWin.on("closed", () => (childWin = null));
  });
};

app.whenReady().then(createWindow);

モーダルダイアログを作成する

子ウィンドウが開かれているとき、親ウィンドウは操作できないようにするモーダルダイアログを作成するには、子ウィンドウ作成時に modal: true を指定します。

main.ts

import { app, BrowserWindow, ipcMain, IpcMainEvent } from "electron";
import * as path from "path";

const createWindow = () => {
  const win = new BrowserWindow({
    webPreferences: {
      preload: path.join(__dirname, "preload.js"),
    },
  });
  win.webContents.openDevTools();
  win.loadFile("index.html");

  ipcMain.on("openDialog", (event: IpcMainEvent, title: string) => {
    const childWin = new BrowserWindow({
      parent: win,
      title: title,
      modal: true,
    });
    childWin.webContents.openDevTools();
    childWin.loadFile("child.html");
  });
};

app.whenReady().then(createWindow);

コメント

コメントする

目次