Reputation: 73
I have 2 BrowserWindow
instances in my electron application, mainWindow
and secondaryWindow
. There is a button in mainWindow
which when clicked should open secondaryWindow
.
Now my issue is that I don't want to be able to click on anything in the mainWindow
until the secondaryWindow
is closed.
The closest I could get was to use mainWindow.hide()
but this just completely hides the window, I want to still see the mainWindow
while the secondaryWindow
is active but it should be disabled / inactive.
Any suggestions?
Upvotes: 0
Views: 2731
Reputation: 945
There are 2 ways to open a child window:
1. from the main process:
You can open a child window from the main process. This is for example useful for a custom window in the menu.
Here you can use the constructor to make it a child of parent
. If the attribute modal
is true, the parent window will not be accessible until the child window is closed.
function createChild(parent, html) {
//creates modal window
child = new BrowserWindow({
width: 786,
height: 847,
parent: parent,
modal: true,
show: false
});
child.loadURL(html);
child.webContents.openDevTools();
child.once("ready-to-show", () => {
child.show();
});
}
2. from the renderer process
Now, we don't always want to send an event over the IPC to the main process just to open a child window, right?
We don't need to. We can use the open
function on our window for that.
For example:
const button = document.querySelector('button')
button.addEventListener('click', e => {
self.open(`file://${__dirname}/child.html`)
})
To make this window a child of your parent and modal, you can register an eventlistener on the parent window:
parent.webContents.on(
"new-window",
(event, url, frameName, disposition, options, additionalFeatures) => {
Object.assign(options, {
parent: parent,
modal: true
});
}
);
With this, when window.open()
is called on the parent window, it will open a modal child window.
Example
main.js
const { app, BrowserWindow } = require("electron");
let win;
function createWindow() {
win = new BrowserWindow({ width: 1000, height: 800 });
win.loadURL(`file://${__dirname}/index.html`);
win.webContents.openDevTools();
win.on("closed", () => {
win = null;
});
win.webContents.on(
"new-window",
(event, url, frameName, disposition, options, additionalFeatures) => {
Object.assign(options, {
parent: win,
modal: true
});
}
);
}
app.on("ready", createWindow);
index.html
<!DOCTYPE html>
<html>
<body>
<p>I am the parent, you can't touch me until you closed my child!</p>
<button>Open child!</button>
<script>
const button = document.querySelector('button')
button.addEventListener('click', e => {
self.open(`file://${__dirname}/child.html`)
})
</script>
</body>
</html>
child.html
<!DOCTYPE html>
<html>
<body>
I'm the child!
</body>
</html>
With electron 5 node integration was disabled in the renderer process by default for security reasons. Since this example uses __dirname
(which is part of the node API) in the renderer process, we need to reintroduce it, because it is not available anymore. In this example I use a preload script for this purpose:
main.js
const { app, BrowserWindow } = require("electron");
let win;
function createWindow() {
win = new BrowserWindow({
width: 1000,
height: 800,
webPreferences: {
preload: `${__dirname}/preload.js`,
},
});
win.loadURL(`file://${__dirname}/index.html`);
win.webContents.openDevTools();
win.on("closed", () => {
win = null;
});
win.webContents.on(
"new-window",
(_event, _url, _frameName, _disposition, options, _additionalFeatures) => {
Object.assign(options, {
parent: win,
modal: true,
});
}
);
}
app.whenReady().then(createWindow).catch(console.error);
preload.js
window.__dirname = __dirname;
index.html
<!DOCTYPE html>
<html>
<body>
<p>I am the parent, you can't touch me until you closed my child!</p>
<button>Open child!</button>
<script>
const button = document.querySelector("button");
button.addEventListener("click", (e) => {
self.open(`file://${__dirname}/child.html`);
});
</script>
</body>
</html>
child.html
<!DOCTYPE html>
<html>
<body>
I'm the child!
</body>
</html>
Upvotes: 2