当前位置:网站首页>Introduction to electron tutorial 3 - process communication
Introduction to electron tutorial 3 - process communication
2022-04-23 19:46:00 【Harm the evil king】
Welcome to Electron The third tutorial of the introductory tutorial , This section is very important ! Interprocess communication (IPC) Is in Electron A key part of building feature rich desktop applications in . Because the main process and rendering process are Electron There are different responsibilities in the process model ,IPC Is the only way to perform many common tasks , For instance from UI Call local API Or trigger from local menu web Changes in content . Let's introduce in detail 3 A common way of communication .
* One way communication between rendering process and main process
stay Electron in , The process is defined by the developer “ passageway ” And ipcMain Module and ipcRenderer Module to communicate . These channels are Any of the ( You can name them as you like ) and Bidirectional ( You can use the same channel name for both modules ). To send a one-way message from the rendering process to the main process IPC news , You can pre render the script again preload.js Use in ipcRenderer send out API Send a message , And then in main.js In the use ipcMain.on receive . You usually use this pattern from your web Call a middle note in the content API. We will demonstrate this pattern by creating a simple application , The application can programmatically change the title of the window .
Let's use code to demonstrate this process , Here are all the codes of the case :
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title> Process of communication </title>
</head>
<body>
Title: <input id="title"/>
<button id="btn" type="button">Set</button>
<script src="./index.js"></script>
</body>
</html>
preload.js
const {
contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
setTitle: (title) => ipcRenderer.send('set-title', title)
})
index.js
const setButton = document.getElementById('btn')
const titleInput = document.getElementById('title')
setButton.addEventListener('click', () => {
const title = titleInput.value
window.electronAPI.setTitle(title)
});
main.js
const {
app, BrowserWindow, ipcMain} = require('electron')
const path = require('path')
function createWindow () {
const mainWindow = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
ipcMain.on('set-title', (event, title) => {
const webContents = event.sender
const win = BrowserWindow.fromWebContents(webContents)
win.setTitle(title)
})
mainWindow.loadFile('index.html')
}
app.whenReady().then(() => {
createWindow()
app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
The operation effect is as follows (GIF It's a little slow , Don't you mind? ):

Here are some key points of the code :
1. Listen for events in the main process
In the main process , We use ipcMain stay set-title Set a... On the channel IPC Monitor , This set-title We are pre rendering the script preload.js The interface channel defined inside .
ipcMain.on('set-title', (event, title) => {
const webContents = event.sender
const win = BrowserWindow.fromWebContents(webContents)
win.setTitle(title)
})
Whenever a message passes set-title Channel incoming , This function will find the attached to the message sender BrowserWindow example , And use win.setTitle Set the title of the application window .
2. Define the interface channel in the preload script
To send a message to the listener created above , You can use ipcRenderer. send out API. By default , The renderer process did not Node.js or Electron Module access . As an application developer , You need to use contextBridge Select which from the preloaded scripts to expose API. here , You will be able to use window.electronAPI.setTitle() function .
const {
contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
setTitle: (title) => ipcRenderer.send('set-title', title)
})
* Two way communication between rendering process and main process
two-way IPC A common application is to invoke the middle note module from the rendering process code and wait for the result. . This can be done by using ipcRenderer.invoke To achieve , call ipcMain.handle pairing . In the following example , We will open a select local file dialog from the rendering process , And return the path of the selected file .
Here are all the codes involved in the case :
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title> Process of communication </title>
</head>
<body>
<button type="button" id="btn">Open a File</button>
File path: <strong id="filePath"></strong>
<script src='./index.js'></script>
</body>
</html>
index.js
const btn = document.getElementById('btn')
const filePathElement = document.getElementById('filePath')
btn.addEventListener('click', async () => {
const filePath = await window.electronAPI.openFile()
filePathElement.innerText = filePath
})
main.js
const {
app, BrowserWindow, ipcMain,dialog} = require('electron')
const path = require('path')
async function handleFileOpen() {
const {
canceled, filePaths } = await dialog.showOpenDialog()
if (canceled) {
return ""
} else {
return filePaths[0]
}
}
function createWindow () {
const mainWindow = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
mainWindow.loadFile('index.html')
}
app.whenReady().then(() => {
ipcMain.handle('openFileDialog', handleFileOpen)
createWindow()
app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
preload.js
const {
contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI',{
openFile: () => ipcRenderer.invoke('openFileDialog')
})
Running effect demonstration :

Here are some key points of the code :
1. Define the event handler function in the main process , And monitor ICP Interface call
In the main process , We will create a call dialog Modular showOpenDialog Function of method handleFileOpen(), The value used to return the file path selected by the user . After the application is ready , It calls ipcMain.handle() To monitor the rendering process ipcRenderer.invoke('openFileDialog') The definition of openFileDialog. When index.js It calls window.electronAPI.openFile() when , Will trigger openFileDialog, After being monitored and processed by the main process , Return results .
2. Call to define the interface through the preloaded script
In the preload script , We opened a single line openFile function , It calls and returns ipcRederer .invoke('openFileDialog').
stay index.js In the code snippet , We're listening to #btn Button click , And call window.electronAPI.openFile() To activate local openFile Dialog box . And then in #filePath Element displays the selected file path .
3. ipcRenderer.invoke An alternative
ipcRenderer.invoke() There are two alternatives :
(1)ipcRenderer.send() : The one-way communication we use can also be used to perform two-way communication . This is Electron 7 Passed before IPC Recommended method for asynchronous two-way communication .
preload.js
const {
ipcRenderer } = require('electron')
ipcRenderer.on('asynchronous-reply', (_event, arg) => {
console.log(arg)
// prints pong
})
ipcRenderer.send('asynchronous-message', 'ping')
main,js
ipcMain.on('asynchronous-message', (event, arg) => {
console.log(arg)
// I will promise ping
event.reply('asynchronous-reply', 'pong')
})
(1) ipcRenderer.sendSync() : This method sends a message to the main process , And wait for the response synchronously .
preload.js
const {
ipcRenderer } = require('electron')
const result = ipcRenderer.sendSync('synchronous-message', 'ping')
console.log(result)
// prints pong
main.js
const {
ipcMain } = require('electron')
ipcMain.on('synchronous-message', (event, arg) => {
console.log(arg)
// prints ping
event.returnValue = 'pong'
})
The structure of this code is very similar to the call model , But for performance reasons , We recommend avoiding this API. Its synchronous nature means that it will block the renderer process , Until a reply is received .
* One way communication from the main process to the rendering process
When a message is sent from the main process to the rendering process , You need to specify which renderer is receiving the message . The message needs to pass through the main process WebContents The instance is sent to the rendering process . This WebContents The instance contains a sent Method , Can be like ipcReender .send Use it like that . To demonstrate this communication mode , A digital counter controlled by the menu bar will be built .
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title> Process of communication </title>
</head>
<body>
Current value: <strong id="counter">0</strong>
<script src='./index.js'></script>
</body>
</html>
preload.js
const {
contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
handleCounter: (callback) => ipcRenderer.on('update-counter', callback)
})
index.js
const counter = document.getElementById('counter')
window.electronAPI.handleCounter((event, value) => {
const oldValue = Number(counter.innerText)
const newValue = oldValue + value
counter.innerText = newValue
event.sender.send('counter-value', newValue)
})
main.js
const {
app, BrowserWindow, Menu, ipcMain} = require('electron')
const path = require('path')
function createWindow () {
const mainWindow = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
const menu = Menu.buildFromTemplate([
{
label: app.name,
submenu: [
{
click: () => mainWindow.webContents.send('update-counter', 1),
label: 'Increment',
},
{
click: () => mainWindow.webContents.send('update-counter', -1),
label: 'Decrement',
}
]
}
])
Menu.setApplicationMenu(menu)
mainWindow.loadFile('index.html')
// Open the DevTools.
mainWindow.webContents.openDevTools()
}
app.whenReady().then(() => {
ipcMain.on('counter-value', (_event, value) => {
console.log(value) // will print value to Node console
})
createWindow()
app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
Running effect demonstration :

Explain part of the code :
We first need to use it in the main process Electron Of Menu The module builds a custom menu , Send... From the main process to the target renderer IPC news . Click the handler to send a message to the renderer process through the counter channel (1 or -1).
const menu = Menu.buildFromTemplate([
{
label: app.name,
submenu: [
{
click: () => mainWindow.webContents.send('update-counter', 1),
label: 'Increment',
},
{
click: () => mainWindow.webContents.send('update-counter', -1),
label: 'Decrement',
}
]
}
])
Menu.setApplicationMenu(menu)
Just like the main process to the previous example , We are preloading the script preload.js Use in contextBridge and ipcRederer The module exposes to the rendering process IPC function :
const {
contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
handleCounter: (callback) => ipcRenderer.on('update-counter', callback)
})
* Communication between rendering processes
stay Electron in , There is no direct method to use between rendering processes ipcMain and ipRenderer Module sends messages , And this communication method is actually very rarely used . Do that , You can use the main process as a message broker between renderers . This will involve sending messages from a renderer to the main process , The main process forwards the message to another renderer , I'm not going to do the demo here .
版权声明
本文为[Harm the evil king]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/04/202204231940533385.html
边栏推荐
- [webrtc] add x264 encoder for CEF / Chromium
- Using oes texture + glsurfaceview + JNI to realize player picture processing based on OpenGL es
- MySQL数据库 - 单表查询(一)
- Summary of several relationships of UML class diagram
- Core concepts of rest
- antd dropdown + modal + textarea导致的textarea光标不可被键盘控制问题
- MySQL practical skills
- A simple (redisson based) distributed synchronization tool class encapsulation
- Mysql database - single table query (I)
- MySQL lock
猜你喜欢

Garbage collector and memory allocation strategy

The most detailed network counting experiment in history (2) -- rip experiment of layer 3 switch

An idea of rendering pipeline based on FBO

Kubernetes入门到精通-裸机LoadBalence 80 443 端口暴露注意事项

Understanding various team patterns in scrum patterns

MySQL syntax collation (3)

2021-2022-2 ACM training team weekly Programming Competition (8) problem solution

MySQL syntax collation

如何在BNB鏈上創建BEP-20通證

山大网安靶场实验平台项目-个人记录(五)
随机推荐
Summary of several relationships of UML class diagram
An algorithm problem was encountered during the interview_ Find the mirrored word pairs in the dictionary
MySQL practical skills
Shanda Wangan shooting range experimental platform project - personal record (V)
Garbage collector and memory allocation strategy
MFC获取本机IP(网络通讯时用得多)
Using oes texture + glsurfaceview + JNI to realize player picture processing based on OpenGL es
MySQL syntax collation (3)
Building googlenet neural network based on pytorch for flower recognition
Prefer composition to inheritance
Zero base to build profit taking away CPS platform official account
Kubernetes入门到精通-裸机LoadBalence 80 443 端口暴露注意事项
php参考手册String(7.2千字)
LPC1768 关于延时Delay时间与不同等级的优化对比
渤海期货这家公司怎么样。期货开户办理安全?
Strange passion
Reflection on the performance of some OpenGL operations in the past
RuntimeError: Providing a bool or integral fill value without setting the optional `dtype` or `out`
Machine learning catalog
Golang timer