当前位置:网站首页>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
边栏推荐
- @Mapperscan and @ mapper
- @MapperScan与@Mapper
- Machine learning catalog
- A brief explanation of golang's keyword "competence"
- 考试系统进入试卷优化思路
- 高效的串口循环Buffer接收处理思路及代码2
- Project training of Software College of Shandong University - Innovation Training - network security shooting range experimental platform (V)
- Scrum Patterns之理解各种团队模式
- Possible root causes include a too low setting for -Xss and illegal cyclic inheritance dependencies
- 【2022】将3D目标检测看作序列预测-Point2Seq: Detecting 3D Objects as Sequences
猜你喜欢
Application of DCT transform
@MapperScan与@Mapper
Possible root causes include a too low setting for -Xss and illegal cyclic inheritance dependencies
Understanding various team patterns in scrum patterns
精简CUDA教程——CUDA Driver API
Zero cost, zero foundation, build profitable film and television applet
antd dropdown + modal + textarea导致的textarea光标不可被键盘控制问题
@Mapperscan and @ mapper
MySQL syntax collation (2)
Is meituan, a profit-making company with zero foundation, hungry? Coupon CPS applet (with source code)
随机推荐
Strange passion
深度分析数据恢复原理——那些数据可以恢复那些不可以数据恢复软件
SRS 的部署
山东大学软件学院项目实训-创新实训-网络安全靶场实验平台(七)
Machine learning catalog
深度学习——特征工程小总结
No, some people can't do the National Day avatar applet (you can open the traffic master and earn pocket money)
uIP1.0 主动发送的问题理解
PHP reference manual string (7.2000 words)
What is a message queue
The textarea cursor cannot be controlled by the keyboard due to antd dropdown + modal + textarea
Distinction between pointer array and array pointer
【h264】libvlc 老版本的 hevc h264 解析,帧率设定
IIS data conversion problem: 16bit to 24bit
考试系统进入试卷优化思路
FFT物理意义: 1024点FFT就是1024个实数,实际进入fft的输入是1024个复数(虚部为0),输出也是1024个复数,有效的数据是前512个复数
Kubernetes introduction to mastery - ktconnect (full name: kubernetes toolkit connect) is a small tool based on kubernetes environment to improve the efficiency of local test joint debugging.
The usage of slice and the difference between slice and array
Decompile and get the source code of any wechat applet - just read this (latest)
[transfer] summary of new features of js-es6 (one picture)