Electron - 窗口焦点通知
本文介绍了在 Electron 应用程序中实现窗口焦点通知的方法。通过使用 IPC 机制和自定义事件,可以在多个窗口之间同步和反映窗口的聚焦状态。
1. 步骤概述
1. 创建新的浏览器窗口,并监听窗口被聚焦的 'focus'
事件。在窗口被聚焦时,发送名为 'window-focused'
的 IPC 消息给主进程。
js
win = new BrowserWindow({
width: 800,
height: 600,
});
// 监听窗口被聚焦事件
win.on('focus', () => {
const winId = win.id;
// 向主进程发送消息,传递当前窗口的 winId
win.webContents.send('window-focused', winId);
});
这段代码是在 Electron 的主进程中创建一个新的 BrowserWindow 窗口,并监听窗口被聚焦的 'focus' 事件。
在 'focus' 事件的回调函数中,首先获取当前窗口的 winId,然后使用 win.webContents.send() 方法向渲染进程发送名为 'window-focused' 的 IPC 消息,并将当前窗口的 winId 作为参数传递。 这样做的目的是,在窗口被聚焦时触发 'focus' 事件,并通过 IPC 将窗口的聚焦状态通知给渲染进程,以便其他相关的窗口能够接收到该消息并响应相应的操作。
2. 在主进程中,使用 ipcMain
监听名为 'window-focused'
的 IPC 消息,并广播窗口聚焦状态给其他窗口。
js
ipcMain.on('window-focused', (event, winId) => {
// 广播窗口聚焦消息给其他窗口
BrowserWindow.getAllWindows().forEach(window => {
window.webContents.send('window-focus-update', winId);
});
});
这段代码是在 Electron 的主进程中使用 ipcMain
监听名为 'window-focused'
的 IPC 消息。当收到该消息时,它会执行回调函数。
在回调函数中,主要的逻辑是广播窗口聚焦消息给其他窗口。它通过使用 BrowserWindow.getAllWindows()
方法获取当前应用程序中的所有窗口,并遍历每个窗口发送名为 'window-focus-update'
的 IPC 消息,将聚焦的窗口的 winId
作为参数传递。
这样做可以实现窗口聚焦更新的事件通知,让其他窗口能够获取到最新的聚焦窗口的信息。
3. 通过接口registerWinFocusCallback注册回调函数 _cb
,用于处理窗口聚焦更新事件。在回调函数被调用时,通过自定义事件 'window-focus-update'
分发窗口的 winId
到文档中。
js
const _cb = winId => void document.dispatch(new CustomEvent('window-focus-update', {details:winId}));
globalThis.globalAPI?.registerWinFocusCallback(_cb);
这段代码是在渲染进程中调用 globalAPI 全局对象的 registerWinFocusCallback 方法,并传递一个回调函数 _cb 作为参数。 在回调函数 _cb 中,它创建了一个自定义事件 'window-focus-update',并通过 document.dispatch() 方法将该事件分发到文档中。事件的细节信息包含了窗口的 winId 参数。
这样做的目的是使用 registerWinFocusCallback 注册一个窗口聚焦更新的回调函数,当窗口聚焦更新事件发生时,回调函数会被调用,并触发自定义事件 'window-focus-update',从而通知其他部分(如之前提到的第一段代码)进行相应处理。
4. 在渲染进程中,使用 contextBridge
和 ipcRenderer
将 globalAPI
对象注入到前端页面的上下文中。
js
const { contextBridge, ipcRenderer } = require('electron');
// 定义全局对象
const globalAPI = {
registerWinFocusCallback: (cb) => {
ipcRenderer.on('window-focus-update', (event, winId) => void cb(winId))},
};
// 将全局对象注入到渲染进程的上下文中
contextBridge.exposeInMainWorld('globalAPI', globalAPI);
这段代码是在 Electron 的渲染进程中使用 contextBridge
和 ipcRenderer
,将一个名为 globalAPI
的全局对象注入到渲染进程的上下文中。
globalAPI
对象包含了一个方法 registerWinFocusCallback
,它用于注册窗口聚焦更新事件的回调函数。具体来说,当收到名为 'window-focus-update'
的 IPC 消息时,该回调函数会被调用,并将窗口的 winId
作为参数传递给回调函数。
通过使用 contextBridge.exposeInMainWorld()
方法,globalAPI
全局对象被暴露给渲染进程的前端页面,在前端页面中可以直接访问和使用其中的方法。
5. 在 React 组件中使用 useEffect
钩子监听窗口聚焦更新事件。根据获取的窗口 ID 更新 SVG 元素的颜色。
js
useEffect(() => {
const changeSvgColor = (color) => {
const svgElement = document.getElementById('state');
if (svgElement) {
svgElement.style.fill = color;
}
};
const handleFocusUpdate = (event) => {
const winId = event.detail;
const _winId = sessionStorage.getItem("winId");
changeSvgColor(winId===_winId?'grey':'white');
};
window.addEventListener('window-focus-update', handleFocusUpdate);
return () => {
window.removeEventListener('window-focus-update', handleFocusUpdate);
};
}, []);
这段代码是使用 React 的 useEffect 钩子实现了监听窗口聚焦更新事件,并根据获取的窗口 ID 更新 SVG 元素的颜色。
在 useEffect 中,首先定义了 changeSvgColor 函数,用于修改 SVG 元素的颜色。然后定义了 handleFocusUpdate 函数,它会在窗口聚焦更新事件触发时被调用。在该函数中,它通过比较传入的窗口 ID (winId) 与存储在 sessionStorage 中的窗口 ID (_winId),确定要设置的颜色,并调用 changeSvgColor 函数进行颜色的更新。 接下来,使用 window.addEventListener 方法将 handleFocusUpdate 函数注册为 'window-focus-update' 事件的监听器。
2. 总结
通过结合上述步骤和示例代码,可以实现在 Electron 应用程序中监听和处理窗口焦点更新事件,并相应地更新界面元素的颜色。这样可以提供一致的用户体验,使用户能够清晰地了解当前具有焦点的窗口。