electron 电子版中两个浏览器窗口之间的通信

ui7jx7zq  于 2022-12-16  发布在  Electron
关注(0)|答案(6)|浏览(572)

我需要建立一个应用程序,将跨越多个监视器屏幕,类似这样:

Electron支持多个窗口,但如何在它们之间通信?

qlzsbp2j

qlzsbp2j1#

要记住的主要一点是,在Electron中,进程间通信是由ipcMain(在主进程中)和ipcRenderer(在所有创建的窗口中)完成的,如下所示:x1c 0d1x从我在GitHub评论中看到的-Renderer示例之间的直接通信是不允许的。所有的东西都必须通过mainProcess。
代码:mainProcess.js:

function createWindow1 () {
  window1 = new BrowserWindow({width: 800,height: 600})
  window1.loadURL(`file://${__dirname}/window1.html`)
  window1.webContents.openDevTools()
  window1.on('closed', function () {
     window1 = null
  })
  return window1
}
function createWindow2 () {
  window2 = new BrowserWindow({width: 1000, height: 600})
  window2.loadURL(`file://${__dirname}/window2.html`)
  window2.webContents.openDevTools()
  window2.on('closed', function () {
    window2 = null
  })
  return window2
}

app.on('ready', () => {
  window1 = createWindow1();
  window2 = createWindow2();

  ipcMain.on('nameMsg', (event, arg) => {
  console.log("name inside main process is: ", arg); // this comes form within window 1 -> and into the mainProcess
  event.sender.send('nameReply', { not_right: false }) // sends back/replies to window 1 - "event" is a reference to this chanel.
  window2.webContents.send( 'forWin2', arg ); // sends the stuff from Window1 to Window2.
});

窗口1.html:

<body>
    <input type="text" id="name" value="" placeholder="Enter your name">
    <button type="button" id="sendName" >Send the name! </button>
</body>
<script>
   // You can also require other files to run in this process
   require('./window1.js')
</script>

窗口1.js:

const ipcRenderer = require('electron').ipcRenderer

let name = document.getElementById('name');

ButtonSendName = document.getElementById('sendName');
ButtonSendName.addEventListener('click', (event) => {
  ipcRenderer.send('nameMsg', name.value);
})

ipcRenderer.on('nameReply', (event, arg) => {
  console.log(arg) // why/what is not right..
});

window2.html:

<body>
  <p id = "showName"></p>
</body>

<script>
  require('./window2.js')
</script>

窗口2.js:

const { ipcRenderer } = require('electron')

showName = document.getElementById('showName')
ipcRenderer.on('forWin2', function (event, arg){
  console.log(arg);
  showName.innerHTML = arg;
});
console.log("I'm Window2");

一个演示会更好,但我不知道如何构建一个电子CodeBin应用程序。

享受电子的力量!

mjqavswn

mjqavswn2#

编辑:我已经为此创建了一个存储库:electron-multi-monitor

我们的项目也有类似的问题,但是两个BrowserWindows都必须来回传递JS对象和函数。
通过IPC调用的解决方案是我们尝试的第一件事,但还不够。当你只需要传递一些小对象时,它工作得很好,但你很快就会达到它的极限,因为电子会序列化通过IPC调用传递的所有数据。
我们继续使用window.opener功能。我们使用electron生成一个main BrowserWindow,然后它通过www.example.com()打开所需数量的side浏览器窗口window.open。Electron可以在生成窗口时定位这些窗口。接下来,每个side窗口都将其HTML DOM注册为main窗口的JS窗口示例。这样main窗口就有了对side窗口的DOM和JS窗口示例的引用。从这里开始,main窗口就可以完全控制所有可用的窗口,并且可以在所有窗口上呈现新的HTML、传递JS对象、调用JS函数......就个人而言,我们使用React Portals来处理不同窗口上的呈现。
目前我还不能分享一个完整的例子,但是如果我有时间的话,我会创建一个github repo。
一些已经可以帮助你前进的事情:

  • 浏览器Windows应具有相同的affinity(请参见BrowserWindow docs
  • 启用网络的nativeWindowOpen首选项

仅供参考:您也可以直接在浏览器中使用此技术,但它们仍然不允许您在窗口中移动

lsmd5eda

lsmd5eda3#

如果你使用window.open()从主窗口的renderer进程打开弹出窗口,你实际上可以通过JS在2个电子窗口之间进行通信。这避免了通过IPC调用进行通信的需要。See Docs
例如:

//renderer process
let popupWindow = window.open(
  './popup.html', 
  'popup'       
  'width=800,height=600'
);

popupWindow.onload = () => {       
  //now we have access to popup window dom   
  popupWindow.document.body.appendChild(myDomElement);
};

请注意,要使此功能正常工作,您需要在最初创建主窗口时设置nativeWindowOpenwebPreferences选项。

// main process
const mainWindow = new BrowserWindow({
  width: 800,
  height: 600,
  webPreferences: {
    nativeWindowOpen: true
  }
})
hmmo2u0o

hmmo2u0o4#

根据您的要求...可以创建SharedWorker作为在窗口之间传输MessagePort的代理。SharedWorker要求所有窗口都从同一源运行(可能无法满足您的要求)。因此,例如,在主窗口中创建一个MessageChannel(其提供两个端口),然后通过SharedWorker将port1传输到一个窗口,将port2传输到另一个窗口。现在两个窗口可以使用postMessage通过端口直接通信。作为奖励,postMessage还支持可传输对象。我一直在尝试这个想法,但还没有完全开发这个库,但你可以从这里正在进行的一些工作中得到这个想法:https://github.com/lneir/electron-direct-comm

bvjveswy

bvjveswy5#

每当我们谈到电子应用程序中从一个窗口到另一个窗口的通信时,您总是要想到IPC系统,即进程间通信。
因此,您将在一个窗口中侦听事件,例如表单提交。
表单提交后,您可以从输入中取出文本,并向Electron应用程序发出一个事件。
然后,电子应用程序将触发自己的事件,并将事件发送到mainWindowmainWindow将接收文本并将其附加到其列表中。
您可以在辅助window.html文件中使用普通JavaScript启动此操作,如下所示:

document.querySelector('form').addEventListener('submit', event => {
    event.preventDefault();
  });

因此,上面的示例假设您正在处理要提交的表单。

ss2ws0br

ss2ws0br6#

这个问题很老了,但我要补充我的意见。
我花了一些时间寻找这个问题的答案,我可以分享我的发现。
如果你想在两个窗口之间直接通信而不需要在主进程中创建监听器,你可以简单地使用ipcRenderer.sendTo函数。
示例:
第一个窗口

ipcRenderer.on("first_window", (_, args) => console.log(args));

ipcRenderer.sendTo(2, "second_window", {
  hello: "world",
});

第二个窗口

ipcRenderer.on("second_window", (_, args) => console.log(args));

ipcRenderer.sendTo(1, "first_window", {
  world: "hello",
});

第一个窗口应在控制台中打印:

{
  world: "hello",
}

第二个窗口应在控制台中打印:

{
  hello: "world",
}

sendTo中的数字是窗口的ID。electronic中的窗口是根据我注意到的情况自动按升序编号的。这意味着您创建的第一个窗口的ID为1,第二个窗口的ID为2,以此类推...
需要注意的是在生产中显示而在开发中不显示的窗口。例如,当你有一个主窗口、启动画面和第三个窗口时,你不一定想在开发模式中显示启动画面,而是在生产模式中显示。
然后,帧将使用-1进行索引。例如,带有启动画面、主窗口、第三个窗口的配置将使用如下索引:

  • 主窗口:1
  • 启动画面:2
  • 第三个窗口:3

但是当你放下启动画面时,你会得到这样的结果。

  • 主窗口:1
  • 第三个窗口:2

https://www.electronjs.org/docs/latest/api/ipc-renderer#ipcrenderersendtowebcontentsid-channel-args

相关问题