Multi-window Applications in Electron application
Managing multiple windows in an Electron application adds complexity but is necessary for many applications. Here's how to handle multi-window scenarios, addressing key aspects like window creation, communication, and lifecycle management. This example uses TypeScript. You would need to adapt it to your specific needs and application structure.
- I. Creating Multiple Windows:
- II. Inter-Window Communication:
- • Example: The main window might open a settings window, and that settings window needs to save settings to a file. IPC is used to communicate back to the main process to handle file saving.
- III. Lifecycle Management:
- IV. Example with Shared Data (More Advanced):
- V. Preventing Multiple Instances:
The main process creates windows. Each window usually loads a separate HTML file (or the same HTML file with different parameters to control the initial UI).
1: import { app, BrowserWindow, ipcMain } from 'electron';
2: import path from 'path';
3:
4: let mainWindow: BrowserWindow | null = null;
5: let settingsWindow: BrowserWindow | null = null;
6:
7: app.on('ready', () => {
8: mainWindow = createMainWindow();
9: // ... other initialization ...
10: });
11:
12: function createMainWindow() {
13: const win = new BrowserWindow({
14: width: 800,
15: height: 600,
16: webPreferences: {
17: preload: path.join(__dirname, 'preload.js'), // Preload for secure IPC
18: // ... other webPreferences ...
19: },
20: });
21: win.loadFile('index.html'); // Load your main Angular app
22: win.on('closed', () => { mainWindow = null; }); // Cleanup on close
23: return win;
24: }
25:
26:
27: ipcMain.on('open-settings', (event) => {
28: settingsWindow = createSettingsWindow();
29: });
30:
31: function createSettingsWindow() {
32: const win = new BrowserWindow({
33: width: 500,
34: height: 400,
35: parent: mainWindow, // Optional: Make it a child window
36: modal: true, // Optional: Make it modal (blocks interaction with parent)
37: webPreferences: {
38: preload: path.join(__dirname, 'preload.js'),
39: // ... other webPreferences ...
40: },
41: });
42: win.loadFile('settings.html'); // Load a separate settings UI
43: win.on('closed', () => { settingsWindow = null; });
44: return win;
45: }
Use Electron's IPC to communicate between windows. The main process often acts as an intermediary.
1: // settings.html (Renderer process in settings window)
2: const { ipcRenderer } = require('electron');
3:
4: // When the user saves settings:
5: ipcRenderer.send('save-settings', settingsData);
6:
7:
8: // electron-main.ts (Main process)
9: ipcMain.on('save-settings', (event, settingsData) => {
10: // Save settingsData to a file (using fs module, electron-store, or other methods)
11: // ... save settings ...
12: });
Properly handle window closing events to avoid memory leaks and ensure resources are released when windows close.
1: // In createMainWindow() and createSettingsWindow()
2: win.on('closed', () => {
3: // Remove references to the window to allow garbage collection
4: if (win === mainWindow) mainWindow = null;
5: else if (win === settingsWindow) settingsWindow = null;
6: // ... cleanup for other related resources
7: });
Sometimes you need to share data between windows. You'll generally need to use the main process to hold and distribute the shared data.
1: ```typescript
2: // electron-main.ts
3: let sharedData = { someValue: 0 };
4:
5: ipcMain.on('get-shared-data', (event) => {
6: event.reply('shared-data', sharedData);
7: });
8: ipcMain.on('update-shared-data', (event, newData) => {
9: sharedData = newData; // Update shared data
10: });
11: ```
Each window would send and receive updates to this shared data. This is a more complex pattern and needs to account for data synchronization and potential race conditions.
It's good practice to prevent multiple instances of your Electron app from running simultaneously.
1: ```typescript
2: const gotTheLock = app.requestSingleInstanceLock();
3:
4: if (!gotTheLock) {
5: app.quit();
6: } else {
7: app.on('second-instance', (event, commandLine, workingDirectory) => {
8: // Focus existing window
9: if (mainWindow) {
10: if (mainWindow.isMinimized()) mainWindow.restore();
11: mainWindow.focus();
12: }
13: });
14: // ... rest of your app initialization ...
15: }
16: ```
These examples demonstrate the fundamental patterns for handling multiple windows. The complexity increases with the number of windows and the level of communication and data sharing you need. Always pay attention to security considerations (data validation and using a preload script). Remember that all database and file system operations should be performed in the main process and that all communication between windows should use IPC. Error handling and efficient resource management (preventing memory leaks) are also very important for any multi-window application.
Electron context:
AngularElectron context:
|