进程间通信是Electron构建程序的关键之一,主要通过ipcMain
和 ipcRenderer
这两个模块来实现,通过开发人员定义的“通道”传递消息来进行通信。
下面展示3个进程间通信的示例。
在项目初始化后并安装electron运行时后,在根目录下创建文件夹html、js,并在文件夹下分别创建index.html和render.js文件。在根目录下创建preload.js文件作为预加载文件。
具体文件结构如下图所示,后面的案例都是按照这个格式:
这里我们通过创建一个简单的程序展示如何从渲染进程发送消息到主进程,这种应用情况很多,比如点击网页中一个按钮发送一个改变窗口大小的消息,这个点击属于渲染进程中的消息,然后消息通过渲染进程发送到主进程,主进程接收到消息后来调整窗口的大小。
首先我们先确定网页布局,建立两个按钮,一个按钮用于最大化窗口,设置为1280×768,另一个按钮用于最小化窗口,设置大小为800×600
渲染进程到主进程(单向)!
然后我们在预加载脚本中通过contextBridge
API向渲染进程暴露两个函数window_maximize和window_minimize,这两个函数通过ipcRenderer.send
API信息通道给主进程发送消息,window_maximize和window_minimize分别用于最大化窗口和最小化窗口。
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
window_maximize: () => ipcRenderer.send('window-maximize'),
window_minimize: () => ipcRenderer.send('window-minimize')
})
下一步我们需要在渲染脚本中调用这两个函数,通过ipcRenderer.send发送信道消息给主进程。
document.getElementById('btn_maximize').addEventListener('click', () => {
window.electronAPI.window_maximize()
});
document.getElementById('btn_minimize').addEventListener('click', () => {
window.electronAPI.window_minimize()
});
主进程通过ipcMain.on
API在window-maximize
和window-minimize
两个通道上设置IPC监听器,接收到来自渲染进程的消息后,要对BrowserWindow窗口大小进行处理,改变窗口大小的函数为BrowserWindow.SetSize(),最大化窗口的宽高设置为1200×768,最小化窗口的宽高设置为800×600。
const {app, BrowserWindow, ipcMain} = require('electron')
const path = require('path')
function createWindow () {
const win = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
}
})
ipcMain.on('window-maximize', (event) => {
win.setSize(1280,768)
})
ipcMain.on('window-minimize', (event) => {
win.setSize(800,600)
})
win.loadFile('html/index.html').then(()=>{})
}
app.whenReady().then(() => {
createWindow()
console.log(path.join(__dirname, 'preload.js'))
app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
这里我们通过继续更改上面的程序展示如何从渲染进程发送消息到主进程并等待返回结果,比如点击最大化或者最小化窗口按钮后,消息通过渲染进程发送到主进程,主进程接收到消息后来调整窗口的大小,等窗口调整完成后,主进程返回一个窗口调整状态显示在程序界面上。
我们在上述第一部分网页界面的基础上加上一个output
输出框,用于显示窗口状态,设置初始的输出内容为“初始为最小化”。
渲染进程到主进程(双向)!
窗口状态:
双向IPC可以通过ipcRenderer.invoke
与 ipcMain.handle
搭配使用来完成,我们将第一个案例中的ipcRenderer.on
替换成ipcRenderer.invoke
,这样就可以异步等待结果。
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
window_maximize: () => ipcRenderer.invoke('window-maximize'),
window_minimize: () => ipcRenderer.invoke('window-minimize')
})
这一步,我们在addEventListener
的回调函数中利用获取预加载脚本中异步函数的返回值并通过innerText
函数显示到output组件当中。
document.getElementById('btn_maximize').addEventListener('click', async () => {
const window_identity = await window.electronAPI.window_maximize()
document.getElementById('window_identity').innerText = window_identity
});
document.getElementById('btn_minimize').addEventListener('click', async() => {
const window_identity = await window.electronAPI.window_minimize()
document.getElementById('window_identity').innerText = window_identity
});
将第一个案例中的ipcMain.on
替换为ipcMain.handle
,用来监听ipcRenderer.invoke
发出的通道信息,执行窗口的大小,并返回窗口标识window_identity
。
const {app, BrowserWindow, ipcMain} = require('electron')
const path = require('path')
let win = null
function createWindow () {
win = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
}
})
win.loadFile('html/index.html').then(()=>{})
}
app.whenReady().then(() => {
const window_identity = "窗口最大化"
ipcMain.handle('window-maximize', async(event) => {
await win.setSize(1280,768)
return window_identity
})
ipcMain.handle('window-minimize', async(event) => {
const window_identity = "窗口最小化"
await win.setSize(800,600)
return window_identity
})
createWindow()
app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
这里我们通过继续更改上面的程序展示如何从主进程发送消息到渲染进程,比如点击窗口右上角的最大化按钮后,会触发窗口的一个resize
事件,通过一个if语句判断窗体是否未最大化,并把消息发送到渲染进程,渲染进程接收到消息后将窗体的最大化状态显示在程序界面的output
里。
这次网页里面只留一个output
用来显示窗口的最大化状态。
主进程到渲染进程!
窗口最大化状态:
通过ipcRenderer.on
建立maximize-identity
通道
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
show_maximize_identity: (listener) => ipcRenderer.on('maximize-identity',listener)
})
在渲染进程中将output
标签的内容显示为从主进程接收到的值。
window.electronAPI.show_maximize_identity((event,value)=>{
document.getElementById('window_identity').innerText = value
})
在app.whenReady()
事件中建立一个win.on
事件用于监听窗体的resize
事件,当窗体最大化时发送"窗口已最大化"消息,当窗体非最大化时发送"窗口未最大化"消息
const {app, BrowserWindow, ipcMain} = require('electron')
const path = require('path')
let win = null
function createWindow () {
win = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
}
})
win.webContents.openDevTools(); //打开调试工具
win.loadFile('html/index.html').then(()=>{})
}
app.whenReady().then(() => {
createWindow()
win.on('resize',()=>{
if (win.isMaximized()){
win.webContents.send('maximize-identity', "窗口已最大化")
}else{
win.webContents.send('maximize-identity', "窗口未最大化")
}
})
app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})