Electron ウィンドウの作成と管理

Electron において、ウィンドウ(Window)はアプリとユーザーが対話するための中心的な媒体です。

すべての可視インターフェースはレンダラープロセス(Renderer Process)内で実行され、これらのウィンドウの作成と制御はメインプロセス(Main Process)が担当します。


ウィンドウの作成と管理

Electron はBrowserWindowクラスを使用してウィンドウを作成します。

メインプロセスでは、次の方法で新しいウィンドウを定義します:

サンプル

const { BrowserWindow } = require('electron')

let mainWindow = new BrowserWindow({
  width: 1200,
  height: 800,
  show: false, // ページの準備ができてから表示する
  webPreferences: {
    preload: path.join(__dirname, 'preload.js'),
  },
})

BrowserWindow 設定オプション

  • width / height:ウィンドウの幅と高さ。
  • minWidth / minHeight:最小サイズの制限。
  • resizable:サイズ変更を許可するかどうか。
  • fullscreen / fullscreenable:全画面表示にするかどうか。
  • frame:ネイティブタイトルバーを表示するかどうか(カスタムタイトルバー使用時はオフにすることが多い)。
  • transparent:透明ウィンドウ(すりガラスやフローティングなどの効果を実現できます)。
  • alwaysOnTop:ウィンドウを常に最前面に表示するかどうか。

ウィンドウのサイズ、位置、状態
API でウィンドウの状態を制御できます:

mainWindow.maximize()   // 最大化
mainWindow.minimize()   // 最小化
mainWindow.restore()    // 还原
mainWindow.setBounds({ x: 100, y: 100, width: 800, height: 600 }) // 调整位置和大小

ウィンドウの変化を監視することもできます:

mainWindow.on('resize', () => console.log('窗口尺寸变化'))
mainWindow.on('move', () => console.log('窗口移动'))

枠なしウィンドウとカスタムタイトルバー
設定frame: false後、タイトルバー領域をカスタマイズし、CSS と JS でドラッグをシミュレートできます:

.titlebar {
  -webkit-app-region: drag;
}

ドラッグ不可領域(ボタンなど)には次を追加する必要があることに注意してください:

.titlebar {
  -webkit-app-region: drag;
}

ウィンドウイベントの監視

mainWindow.on('close', (e) => {
  e.preventDefault()
  mainWindow.hide()
})

よく使われるイベントは次のとおりです:

  • ready-to-show:ページの読み込みが完了し、安全に表示できます。
  • focus / blur:ウィンドウがフォーカスを取得または喪失したとき。
  • closed:ウィンドウが破棄されたとき。

ページコンテンツの読み込み

Electron ウィンドウは、ローカルの HTML ファイルやリモートのウェブサイトを読み込めます。

ローカル HTML ファイルの読み込み

mainWindow.loadFile('index.html')

リモート URL の読み込み

mainWindow.loadURL('https://example.com')

フロントエンドフレームワークの使用
Vue、React、Angular などのモダンフレームワークを使用している場合、ビルド済みの静的ファイルをウィンドウに読み込めます:

mainWindow.loadFile(path.join(__dirname, 'dist/index.html'))

または開発モードでローカルサーバーを読み込みます:

mainWindow.loadURL('http://localhost:5173')

ウィンドウ間通信

マルチウィンドウアプリでは、ウィンドウ間でデータを渡したり、動作を制御したりする必要がある場合があります。

親子ウィンドウの関係
新しいウィンドウを作成するときに指定できます:parent:

let child = new BrowserWindow({
  parent: mainWindow,
  modal: true, // 模态窗口
  width: 400,
  height: 300,
})

親ウィンドウが閉じると、子ウィンドウも自動的に閉じます。

マルチウィンドウでのデータ共有
メインプロセスを仲介として、異なるレンダラープロセス間でデータを渡すことができます。また、グローバルオブジェクトやipcMain / ipcRenderer。

ウィンドウメッセージの送受信
メインプロセスはターゲットウィンドウを直接操作できます:

child.webContents.send('update-data', someData)

子ウィンドウで受信します:

const { ipcRenderer } = require('electron')
ipcRenderer.on('update-data', (event, data) => {
  console.log(data)
})

インターフェースの最適化

スプラッシュスクリーン
メインウィンドウの読み込みが遅い場合、軽量なスプラッシュウィンドウを先に表示できます:

const splash = new BrowserWindow({ width: 400, height: 300, frame: false })
splash.loadFile('splash.html')

mainWindow.once('ready-to-show', () => {
  splash.close()
  mainWindow.show()
})

ウィンドウ表示の最適化
白画面のちらつきを防ぐための一般的なテクニックは次のとおりです:

  • 使用しshow: falseウィンドウを作成し、読み込み完了後にshow()。
  • レンダリングページで背景色を設定します。
  • リソース(アイコン、フォント、スタイル)をプリロードします。

GPU アクセラレーションを有効にするか、ハードウェアアクセラレーションを無効にします(状況に応じて)。

  • CSS で複雑なアニメーションやグラデーションを避けます。
  • ダブルバッファレンダリングを使用して、描画のちらつきを減らします。
  • マルチウィンドウ Electron アプリ(スプラッシュページ、メインインターフェース、子ウィンドウを含む)

マルチウィンドウ Electron アプリ(スプラッシュページ、メインインターフェース、子ウィンドウを含む)

main.js(メインプロセス)

my-electron-app/
├── package.json
├── main.js             # 主进程入口
├── preload.js          # 预加载脚本
├── splash.html         # 启动画面
├── index.html          # 主窗口页面
├── child.html          # 子窗口页面
└── renderer.js         # 渲染进程逻辑

サンプル

サンプル

const { app, BrowserWindow, ipcMain } = require('electron')
const path = require('path')

let mainWindow, splash, childWindow

function createSplash() {
  splash = new BrowserWindow({
    width: 400,
    height: 300,
    frame: false,
    transparent: true,
    alwaysOnTop: true,
  })
  splash.loadFile('splash.html')
}

function createMainWindow() {
  mainWindow = new BrowserWindow({
    width: 1200,
    height: 800,
    show: false,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
    },
  })

  mainWindow.loadFile('index.html')

  // プロセス間通信
  mainWindow.once('ready-to-show', () => {
    if (splash) splash.close()
    mainWindow.show()
  })

  mainWindow.on('closed', () => (mainWindow = null))
}

function createChildWindow() {
  childWindow = new BrowserWindow({
    parent: mainWindow,
    modal: true,
    width: 400,
    height: 300,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
    },
  })
  childWindow.loadFile('child.html')
}

(プリロードスクリプト)
ipcMain.on('open-child', () => {
  if (!childWindow) createChildWindow()
})

ipcMain.handle('get-app-info', () => {
  return {
    name: app.getName(),
    version: app.getVersion(),
  }
})

app.on('ready', () => {
  createSplash()
  setTimeout(() => createMainWindow(), 1500)
})

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') app.quit()
})

preload.jsindex.html(メインウィンドウ)
const { contextBridge, ipcRenderer } = require('electron')

contextBridge.exposeInMainWorld('electronAPI', {
  openChild: () => ipcRenderer.send('open-child'),
  getAppInfo: () => ipcRenderer.invoke('get-app-info'),
})

サンプル

サンプル

<!DOCTYPE html>
<html lang="zh">
<head>
  <meta charset="UTF-8" />
  <title>Electron アプリへようこそ</title>
  <style>
    body { font-family: sans-serif; text-align: center; margin-top: 100px; }
    button { padding: 10px 20px; font-size: 16px; cursor: pointer; }
  </style>
</head>
<body>
  <h1>子ウィンドウを開く</h1>
  <p id="info"></p>
  <button id="open">child.html(子ウィンドウ)</button>

  <script src="renderer.js"></script>
</body>
</html>

サンプル

サンプル

<!DOCTYPE html>
<html lang="zh">
<head>
  <meta charset="UTF-8" />
  <title>これは子ウィンドウです</title>
  <style>
    body { font-family: sans-serif; text-align: center; margin-top: 100px; }
  </style>
</head>
<body>
  <h2>メインウィンドウからの指示を受け取ることができます</h2>
  <p>splash.html(スプラッシュ画面)</p>
</body>
</html>

サンプル

サンプル

<!DOCTYPE html>
<html lang="zh">
<head>
  <meta charset="UTF-8" />
  <title>アプリを起動しています。しばらくお待ちください...</title>
  <style>
    body {
      display: flex;
      justify-content: center;
      align-items: center;
      height: 100vh;
      background: linear-gradient(135deg, #8EC5FC, #E0C3FC);
      font-family: sans-serif;
    }
    h1 {
      font-size: 28px;
      color: #333;
    }
  </style>
</head>
<body>
  <h1>renderer.js(レンダーロジック)</h1>
</body>
</html>

サンプル

サンプル

const info = document.getElementById('info')
const btn = document.getElementById('open')

`アプリ名:$
window.electronAPI.getAppInfo().then((appInfo) => {
  info.textContent =| バージョン:${appInfo.name}// 子ウィンドウを開く{appInfo.version}`
})

実行後の流れは次のとおりです:
btn.addEventListener('click', () => {
  window.electronAPI.openChild()
})

起動時には

  1. スプラッシュ画面が表示されます。読み込み完了後、スプラッシュページを自動的に閉じて表示されるのは(splash.html)。
  2. メインウィンドウです。メインウィンドウはボタンで。
  3. 子ウィンドウを開き、IPC 通信機能を紹介します。メインウィンドウは
  4. Preload による安全な API 公開を使用し、Node.js への直接アクセスを防いでいます。すべてのウィンドウで
  5. イベント監視遅延表示、などの最適化戦略を使用し、白画面やちらつきを防いでいます。その他の拡張
AI 思考中...