突然始めたから初心者レベルやで。
適当にプロジェクト作って、こんな画面を作成。
(プロジェクト作成方法とかは何がいいのか知らないので割愛)
いろいろ検索するとだいたいレンダラープロセス(HTML)のほうでNodeの機能(主にremote)を呼び出してるんだけど、
現在はデフォルトで非推奨らしいのでcontextBridgeを使って、なんでもメインプロセスで動かす必要があるらしい。
まぁそりゃレンダラーのほうでなんでも実行されたらセキュリティ的にあぶないし。
ボタンでダイアログ
とりあえずボタン押したらダイアログを出す。
contextBridgeに関しては以下のページがすごく参考になりました。
https://blog.katsubemakito.net/nodejs/electron/ipc-for-contextbridge
まずはpreload.jsを作成して、レンダラー → メインを作成。名前は適当に「dialogMsg」にしてます。
const { ipcRenderer, contextBridge } = require("electron");
contextBridge.exposeInMainWorld("electron", {
// レンダラー → メイン
dialogMsg: async (data) => await ipcRenderer.invoke("dialogMsg", data),
});
メインプロセス側のindex.jsはipcMainでダイアログを出す処理を作成。
// Native
const { join } = require("path");
const { format } = require("url");
// Packages
const { BrowserWindow, app, ipcMain, dialog} = require("electron");
const isDev = require("electron-is-dev");
const prepareNext = require("electron-next");
// Prepare the renderer once the app is ready
app.on("ready", async () => {
await prepareNext("./renderer");
// ウィンドウ作成
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: join(__dirname, "preload.js"),
},
});
// URL作成
const url = isDev
? "http://localhost:8000"
: format({
pathname: join(__dirname, "../renderer/out/index.html"),
protocol: "file:",
slashes: true,
});
if (isDev) {
// 開発者ツール
mainWindow.webContents.openDevTools();
}
mainWindow.loadURL(url);
});
// 終了処理
app.on("window-all-closed", app.quit);
// 以下レンダーとの通信
ipcMain.handle("dialogMsg", (event, data) => {
const w = BrowserWindow.getFocusedWindow();
dialog.showMessageBox(w, {
type: "info",
title: "タイトル",
message: data,
});
return;
});
レンダラープロセス側のindex.jsではonClickイベントでdialogActionを呼び出して、
メインプロセス側の処理を呼び出し。
import { useState, useEffect } from "react";
export default function Home() {
// 初回のイベント
useEffect(() => {
console.log("useEffect");
}, []);
// ボタンイベント
const dialogAction = async (event) => {
console.log("dialogAction");
await window.electron.dialogMsg("テストだよ");
};
return (
<div className="main">
<h1 id="test">
右クリックサンプル
</h1>
<button id="test_button" type="button" onClick={dialogAction}>
TEST
</button>
<style jsx>{`
h1 {
font-size: 20px;
}
`}</style>
<style jsx global>{`
body {
background-color: white;
}
`}</style>
</div>
);
}
h1タグで右クリック
まぁダイアログとほぼ同じですね。まぁあれなんでレンダラーのほうのイベントもキックします。
まずはpreload.jsを修正。レンダラー → メインのpopupMenuを追加して、メイン → レンダラーを追加しました。
const { ipcRenderer, contextBridge } = require("electron");
contextBridge.exposeInMainWorld("electron", {
// レンダラー → メイン
dialogMsg: async (data) => await ipcRenderer.invoke("dialogMsg", data),
popupMenu: async (data) => await ipcRenderer.invoke("popupMenu", data),
// メイン → レンダラー
on: (channel, callback) =>
ipcRenderer.on(channel, (event, argv) => callback(event, argv)),
});
次にメインプロセス側でメニュー作成とそれを表示するipcMainを追加。
// メニューを作成
const menu = Menu.buildFromTemplate([
{
label: "Test Menu",
click: () => {
// ウィンドウを取得して、レンダラーに通知
const w = BrowserWindow.getFocusedWindow();
w.webContents.send("popuo-return");
},
},
{ type: "separator" },
{ role: "quit" },
]);
// コンテキストメニューを表示
ipcMain.handle("popupMenu", (event) => {
const w = BrowserWindow.getFocusedWindow();
menu.popup(w);
return;
});
レンダラー側ではonContextMenuを追加してcontextMenuイベントを呼び出して、ContextMenuを表示して、
メニューを選択したら、popuo-returnを起動して、レンダラー側でAlertを表示。
import { useState, useEffect } from "react";
export default function Home() {
// 初回のイベント
useEffect(() => {
console.log("useEffect");
window.electron.on("popuo-return", (event) => {
alert("右クリックからのアラート");
});
}, []);
// 右クリックメニュー
const contextMenu = async (event) => {
console.log("contextMenu", event.currentTarget);
event.preventDefault();
await window.electron.popupMenu();
};
// ボタンイベント
const dialogAction = async (event) => {
console.log("dialogAction");
await window.electron.dialogMsg("テストだよ");
};
return (
<div className="main">
<h1 id="test" onContextMenu={contextMenu}>
右クリックサンプル
</h1>
<button id="test_button" type="button" onClick={dialogAction}>
TEST
</button>
<style jsx>{`
h1 {
font-size: 20px;
}
`}</style>
<style jsx global>{`
body {
background-color: white;
}
`}</style>
</div>
);
}
以上です。