I am writing an Eletron program. In the program there is one index-window which is created by the main process (main.js). In this window there is a list of files (images). When I click on one of the files in that list I want to start a second window that displays that file.
That second window is started by the renderer process of the index-window (index.js). How can I communicate between the renderer process of the index-window and the renderer process of the second window?
Code:
Creating the index-window from the main process in main.js:
let win;
function createWindow(){
// Create the browser window.
win = new BrowserWindow({width: 1024, height: 768, minWidth: 800, minHeight: 600, show: false, icon: 'files/images/icon.png'});
win.loadURL(`file://${__dirname}/files/html/index.html`);
win.once('ready-to-show', () => {
win.show()
})
// Emitted when the window is closed.
win.on('closed', () => {
win = null;
});
}
app.on('ready', createWindow);
In the index.html index.js (renderer process) is started:
<script src="../javascript/index.js"></script>
In index.js the function create_sprite_window() is called which creates a child window:
const fs = require('fs');
const path = require('path');
const {BrowserWindow} = require('electron').remote
let child_windows = [];
function create_child_window(URL, width, height){
let rem_win = require('electron').remote.getCurrentWindow();
let new_win = new BrowserWindow({width: width, height: height, minWidth: 400, minHeight: 300, show: false, parent: rem_win, minimizable: true, maximizable: true, skipTaskbar: true});
child_windows[child_windows.length] = new_win;
console.log(child_windows);
new_win.loadURL(URL);
new_win.once('ready-to-show', () => {
new_win.show()
})
return new_win;
}
function create_sprite_window(){
new_win = create_child_window(`file://${__dirname}/../html/sprite_manager.html`, 800, 400);
}
The child windows are stored in the array child_windows.
Is it possible to then send the path of the image to the second window or, alternatively, edit the <img> tag of the second window (setting the source of the <img> tag in the second window to the image with getElementById.src = path;) from the index-window?.
I have found the answer by myself.
To show the correct image in the second renderer window, I add a GET parameter to the URL which contains the path of the image.
Related
I am trying to send a parameter and its property from the main process to the renderer process, then append that property value as a string onto a div in my html/ child window. However, the renderer process cannot find the Id I have specified and returns the error:
Cannot read property 'append' of null at EventEmitter.<anonymous>
I thought I could get around this error by sourcing the renderer file to my html but that makes the html look for other elements that are also sourced to that renderer process as I have multiple html files connected to it and it doesn't work either way.
So after this, I created another javascript file specifically for that html window but that window cannot recieve events from the main process.
Here is my current code:
HTML
<div id="brst_files">
</div>
<script type="text/javascript" src="./renderer.js">
</script>
<script>
//Open the dialog for burst button
let brstfile = document.getElementById('brst_add_files')
brstfile.addEventListener('click', function(event){
console.log('recieved')
ipcRenderer.send('brst_add_files')
console.log('add file')
})
ipcRenderer.on('brstfiles', function(event){
console.log('html recieved')
document.getElementById('brst_files').append('data.filePath')
console.log('file path recieved')
})
</script>
Main
//Open burst window dialog menu
ipcMain.on('brst_add_files', function(event){
console.log('adding files')
dialog.showOpenDialog({properties:['openFile','dontAddToRecent','multiSelections'],
filters: [
{ name: 'All Files', extensions: ['*'] }
//Recieve and send the file path data
]}).then((data) => {
console.log(data.filePaths);
mainWindow.webContents.send('brstfiles', data.filePaths)
console.log('file path sent')
});
})
}
Renderer
//Burst create window
let brstwindow = new BrowserWindow({
width:400,
height:415,
frame: false,
useContentSize: true,
backgroundColor: '#00000000',
alwaysOnTop: false,
transparent: true,
resizable: true,
webPreferences: {
nodeIntegration: true,
enableRemoteModule: true,
useContentSize:true
}
});
brstwindow.loadURL(url.format({
pathname: path.join(__dirname, 'Burstcreate.html'),
protocol: 'file',
slashes:true
}));
brstwindow.webContents.openDevTools()
brstwindow.hide()
//Open the burst button window
let brstopen = document.getElementById('burstbtn')
brstopen.addEventListener('click', function(event){
brstwindow.show()
})
//Recieve file path from main and append to div
ipcRenderer.on('brstfiles', function(event){
console.log('html recieved')
document.getElementById('brst_files').append('data.filePath')//I know this just appends a string
console.log('file path recieved')
})
Other renderer
const { ipcRenderer, webContents} = require('electron');
const app = require('electron').remote.app;
const electron = require('electron');
const { get } = require('http');
const BrowserWindow = electron.remote.BrowserWindow;
const path = require('path');
const { on } = require('process');
const {dialog} = require('electron')
const url = require('url');
//Recieved the file path back from main and appending it to div
ipcRenderer.on('brstfiles', function(event){
console.log('html recieved')
document.getElementById('brst_files').append('data.filePath')
console.log('file path recieved')
})
So my main question is: How can I find DOM elements in a child window from renderer? Should I do everything from the main process?
Extra question: How do I recieve parameters from main process in the renderer process?
There is no explicit example of how to position your ELECTRON JS app to a specific area. The only syntax is available on GitHub, and it does not describe it well.
It's quite straight forward. Consider this code that positions the mainWindow once the ready event fires. You should be able to drop in the 'ready' event below to demonstrate the positioner.
// load the module
const Positioner = require('electron-positioner');
let mainWindow = null;
// create the main window
async function createWindow () {
mainWindow = new BrowserWindow({
height: 420,
width: 600,
x: 0, // default position left
y: 0, // default position top
show: false,
webPreferences: {
nodeIntegration: true,
preload: path.join(__dirname, 'node_modules', 'electron', 'dist', 'electron-bridge.js')
}
});
// reposition after creating the window.
app.on('ready', async () => {
await createWindow();
let positioner = new Positioner(mainWindow);
positioner.move('bottomRight');
});
Of course this affect may be achieved with the x and y values via the BrowserWindow constructor, but it is quite handy to have canned positions provided by the module.
I'd like to have one single Electron window, split in two parts:
the left part is a BrowserWindow loading https://gmail.com
the right part is another BrowserWindow loading Gmail too, but I'd like these two browsers to be "independent", i.e. the cookies/LocalStorage/etc. should be independent (like if we have a normal Chrome window vs. a incognito window) ; thus allowing to have one Gmail account on left / another account connected on the right part
some other UI buttons on top of the single Electron window.
This code works, but it creates 2 windows instead of one:
const { app, BrowserWindow } = require('electron')
const path = require('path')
app.once('ready', () => {
let win = new BrowserWindow({show: false})
win.once('show', () => { win.webContents.executeJavaScript('validateFlights()') })
win.loadURL('https://www.gmail.com')
win.show()
let win2 = new BrowserWindow({show: false})
win2.once('show', () => { win.webContents.executeJavaScript('validateFlights()') })
win2.loadURL('https://www.gmail.com')
win2.show()
})
How to have them in one window?
A little late, but to add two browsers within one window you have to use BrowserWindow.addBrowserView instead of BrowserWindow.setBrowserView. You'll get the following:
const { BrowserView, BrowserWindow, app } = require('electron')
function twoViews () {
const win = new BrowserWindow({ width: 800, height: 600 })
const view = new BrowserView()
win.addBrowserView(view)
view.setBounds({ x: 0, y: 0, width: 400, height: 300 })
view.webContents.loadURL('https://electronjs.org')
const secondView = new BrowserView()
win.addBrowserView(secondView)
secondView.setBounds({ x: 400, y: 0, width: 400, height: 300 })
secondView.webContents.loadURL('https://electronjs.org')
app.on('window-all-closed', () => {
win.removeBrowserView(secondView)
win.removeBrowserView(view)
app.quit()
})
}
app.whenReady().then(twoViews)
Once you create two BrowserView objects, you just add them to the window. You'll also want to remove the views when tearing down the application. If you don't you might get a segmentation fault.
What you are looking for is BrowserView
From the docs:
A BrowserView can be used to embed additional web content into a BrowserWindow. It is like a child window, except that it is positioned relative to its owning window. It is meant to be an alternative to the webview tag.
It looks like this is what you want, the views can render separate HTML pages and position them relatively inside the same browser window.
// In the main process.
const { BrowserView, BrowserWindow } = require('electron')
let win = new BrowserWindow({ width: 800, height: 600 })
win.on('closed', () => {
win = null
})
let view = new BrowserView({
webPreferences: {
nodeIntegration: false
}
})
win.setBrowserView(view)
view.setBounds({ x: 0, y: 0, width: 300, height: 300 })
view.webContents.loadURL('https://electronjs.org')
I want the user to be able to pick a folder from the folder dialog box.
So far, I've tried following this tutorial unsuccessfully.
I got stuck on the part of
exports.selectDirectory = function () {
// dialog.showOpenDialog as before
}
What do I need to do in order to retrieve the full path of the selected folder?
Thanks!
Dialog api is available in main process(https://electron.atom.io/docs/).
To create a dialog box you will have to tell your main process to do so by sending a message from renderer process.
Try this code:
// in your renderer process:-
const ipcRenderer = require('electron').ipcRenderer;
ipcRenderer.send('selectDirectory');
//in you main process:-
const electron = require('electron');
const ipcMain = electron.ipcMain;
const dialog = electron.dialog;
//hold the array of directory paths selected by user
let dir;
ipcMain.on('selectDirectory', function() {
dir = dialog.showOpenDialog(mainWindow, {
properties: ['openDirectory']
});
});
Note: mainWindow here, it's the parent browserWindow which will hold the dialog box.
You need to use electron remote
const {dialog} = require('electron'),
WIN = new BrowserWindow({width: 800, height: 600})
/*
//renderer.js - a renderer process
const {remote} = require('electron'),
dialog = remote.dialog,
WIN = remote.getCurrentWindow();
*/
let options = {
// See place holder 1 in above image
title : "Custom title bar",
// See place holder 2 in above image
defaultPath : "D:\\electron-app",
// See place holder 3 in above image
buttonLabel : "Custom button",
// See place holder 4 in above image
filters :[
{name: 'Images', extensions: ['jpg', 'png', 'gif']},
{name: 'Movies', extensions: ['mkv', 'avi', 'mp4']},
{name: 'Custom File Type', extensions: ['as']},
{name: 'All Files', extensions: ['*']}
],
properties: ['openFile','multiSelections']
}
//Synchronous
let filePaths = dialog.showOpenDialog(WIN, options)
console.log('filePaths)
//Or asynchronous - using callback
dialog.showOpenDialog(WIN, options, (filePaths) => {
console.log(filePaths)
})
I am attempting to make a pdf viewer app using electron and electron-pdf-window
the code below works when i want to open from a URL file path, but when i tried to open a pdf from my local files using the file:/// the application download the pdf instead of viewing it on my window.
const { app } = require('electron')
const PDFWindow = require('electron-pdf-window')
app.on('ready', () => {
const win = new PDFWindow({
width: 800,
height: 600
})
win.loadURL('file://///C://username/desktop/myfile.pdf')
})
I tried also below code but below error displays.
TypeError: Cannot match against 'undefined' or 'null'.
const { BrowserWindow } = require('electron').remote
const PDFWindow = require('electron-pdf-window')
const win = new BrowserWindow({ width: 800, height: 600 })
PDFWindow.addSupport(win)
win.loadURL('file://///C://username/desktop/myfile.pdf')
Is there another way to open local pdf files from my PC directory?
Base on this readme, https://github.com/electron/electron/blob/master/docs/api/browser-window.md
you can do it something like
win.loadURL(`file://${__dirname}/app/index.html`)
but you have to put this inside app.on('ready', function() {} to avoid getting the Cannot create BrowserWindow before app is ready error.
Reason why that error appears
Because the app is not yet ready and is still loading
You need Modify electron-pdf-window package.
Open electron-pdf-window/index.js
Go to comment line 23 const->let fileUrl = url.replace(/^file:///i, '');
firstly change const via let,then add after this code
fileUrl = fileUrl.replace('/', '');
you can use normally ;
const w= new BrowserWindow({
width: 1200,
height: 920,
webPreferences: {
nodeIntegration: true,
contextIsolation: true
}
});
PDFWindow.addSupport(w)
w.loadURL(url.format ({
pathname: path.join(__dirname, '../pdf/123.pdf'),
protocol: 'file:',
slashes: true
}));