Multi window - PublicVar/electron-wiki GitHub Wiki

It's easier to create single window app using angular, react, etc. You don't need to worry about communicating with different windows, processes, etc.

But, let's try to create an app with several windows.

Main and Renderer

Before starting we have to understand 2 concepts Main process and Renderer process.

Electron has 2 types of processes.

  • The Main process is responsible for interacting with the native GUI of your operating system and creates the GUI of your application (your application windows)
  • The Renderer process is your html (with js, css included) rendered file, the window. It's the Main process that created the renderer process

ipcMain and ipcRenderer

The different windows (rendered processes) can't communicate directly between themselves. Indeed, a window can't have the instance of the future created window.

This is the reason why we have to go through the Main process to dispatch the messages.

To do that we use ipcMain and ipcRenderer. it's 2 objects instances of EventEmitter. As you can guess, we will use some events and listeners.

To dispatch an event from a window to the main process or to listen some events coming from the Main process, we use ipcRenderer. And from the Main process to listen or to dispatch event to rendered windows we use ipcMain.

Example

Let's create an app with 2 windows. our app.js (electron entry point) look like this:

//app.js
const electron = require('electron')
const app = electron.app
const BrowserWindow = electron.BrowserWindow
const ipcMain = electron.ipcMain;
const path = require('path')
const url = require('url')

let mainWindow
let secondWindow

function createWindow () {
  // Create 1st window
  mainWindow = new BrowserWindow({width: 800, height: 600})

  mainWindow.loadURL(url.format({
    pathname: path.join(__dirname, 'mainWindow.html'),
    protocol: 'file:',
    slashes: true
  }))

  mainWindow.webContents.openDevTools()

  mainWindow.on('closed', function () {
    mainWindow = null
  })
  
  //Create 2nd window
  secondWindow = new BrowserWindow({
    width: 75,
    height: 500,
    show: false
  })
  secondWindow.setAlwaysOnTop(true)

  secondWindow.loadURL(url.format({
    pathname: path.join(__dirname, 'second.html'),
    protocol: 'file:',
    slashes: true
  }))

}
app.on('ready', createWindow)

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

app.on('activate', function () {
  if (mainWindow === null) {
    createWindow()
  }
})

//Listen to 'show-second' event from rendered process
ipcMain.on('show-second',(event, arg)=>{
  secondWindow.show()
})

As you can see, we created 2 windows mainWindow and secondWindow. The secondWindow is not visible when the app starts :

//app.js
//...some codes
secondWindow = new BrowserWindow({
    width: 75,
    height: 500,
    show: false
  })
//...some codes

We want, when we click on a button in the mainWindow it displays the secondWindow.

Let's take a look in our mainWindow html file and see the button and the code that allows us to communicate with the Main process.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Hello World!</title>
    <link rel="stylesheet" type="text/css" href="css/main.css">
  </head>
  <body>
     <button type="button" onclick="show()">Show second window</button>
  </body>
 
  <script>
    const {ipcRenderer} = require('electron')
    function show(){
        ipcRenderer.send('show-second');  //dispatch the event 'show-second' to the main process
    }
  </script>
</html>

Note: for the example the event code is directly into the html file but it's better to put the code in a seperate js file and linked in the html files

If you look back to our app.js code you will notice that we already have the listener in the Main process:

//app.js
const ipcMain = electron.ipcMain;

//...some codes

//Listen to 'show-second' event from rendered process
ipcMain.on('show-second',(event, arg)=>{
  secondWindow.show()//Show the second window
})

To dispatch event from main process to a Renderer process

You have to do something a little bit different. You have to send the event throught the webContents of the renderer process :

//Sending a changing color event from the main process to the secondWidow
ipcMain.on('color',(event, color)=>{
  secondWindow.webContents.send('newColor',color)
})

To sum up, the windows (rendered process) can't communicate directly between themselves. They had to pass through the Main process.

To go further

Build a mini drawing app (HTML, CSS, javascript) with 2 different windows:

  • One for the main drawing area
  • Another one for the toolbox (color selector of the pencil, size selector, etc.)

If you don't know where to start, you can take a look at this tutorial CREATE A DRAWING APP WITH HTML5 CANVAS AND JAVASCRIPT

⚠️ **GitHub.com Fallback** ⚠️