Electron -- 窗口焦点通知

4,480 阅读4分钟

Electron - 窗口焦点通知

本文介绍了在 Electron 应用程序中实现窗口焦点通知的方法。通过使用 IPC 机制和自定义事件,可以在多个窗口之间同步和反映窗口的聚焦状态。

1. 步骤概述

1. 创建新的浏览器窗口,并监听窗口被聚焦的 'focus' 事件。在窗口被聚焦时,发送名为 'window-focused' 的 IPC 消息给主进程。

 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 消息,并广播窗口聚焦状态给其他窗口。

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 到文档中。

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. 在渲染进程中,使用 contextBridgeipcRendererglobalAPI 对象注入到前端页面的上下文中。

const { contextBridge, ipcRenderer } = require('electron');

// 定义全局对象
const globalAPI = {
  registerWinFocusCallback: (cb) => {
    ipcRenderer.on('window-focus-update', (event, winId) => void cb(winId))},
};

// 将全局对象注入到渲染进程的上下文中
contextBridge.exposeInMainWorld('globalAPI', globalAPI);

这段代码是在 Electron 的渲染进程中使用 contextBridgeipcRenderer,将一个名为 globalAPI 的全局对象注入到渲染进程的上下文中。

globalAPI 对象包含了一个方法 registerWinFocusCallback,它用于注册窗口聚焦更新事件的回调函数。具体来说,当收到名为 'window-focus-update' 的 IPC 消息时,该回调函数会被调用,并将窗口的 winId 作为参数传递给回调函数。

通过使用 contextBridge.exposeInMainWorld() 方法,globalAPI 全局对象被暴露给渲染进程的前端页面,在前端页面中可以直接访问和使用其中的方法。

5. 在 React 组件中使用 useEffect 钩子监听窗口聚焦更新事件。根据获取的窗口 ID 更新 SVG 元素的颜色。

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 应用程序中监听和处理窗口焦点更新事件,并相应地更新界面元素的颜色。这样可以提供一致的用户体验,使用户能够清晰地了解当前具有焦点的窗口。