为什么我的 ipcMain 没有发送到 Electron 中的 ipcRenderer?
Why is my ipcMain not sending to ipcRenderer in Electron?
电子新手 我已经弄清楚如何从 Renderer 发送到 Main 但我正在努力学习如何去从 Main 到 Renderer。在我的研究中,我读到:
IPC send from main process to renderer 并尝试过:
main.js:
const { app, ipcMain, Menu } = require('electron')
const appVersion = process.env.npm_package_version
const mainWindow = require('./renderer/mainWindow')
app.on('ready', () => {
mainWindow.createWindow(),
console.log(`Trying to send app version to renderer: ${appVersion}`),
mainWindow.webContents.send('app-version', appVersion),
Menu.setApplicationMenu(mainMenu)
})
但我收到以下错误:
Uncaught Exception TypeError Cannot read property 'send' of undefined
阅读“Send sync message from IpcMain to IpcRenderer - Electron”后我尝试了:
ipcMain.on('app-version', (event) => {
console.log(`Sent: ${appVersion}`)
event.sender.send(appVersion)
}),
但没有任何反应或出现错误。我的renderer.js:
const { ipcRenderer } = require('electron')
ipcRenderer.on('app-version', (event, res) => {
console.log(res)
})
为什么我的 ipcMain 没有发送到我的 ipcRenderer?
编辑:
mainWindow.js:
// Modules
const { BrowserWindow } = require('electron')
// export mainWindow
exports.createWindow = () => {
// BrowserWindow options
// https://electronjs.org/docs/api/browser-window#new-browserwindowoptions
this.win = new BrowserWindow({
minWidth: 400,
minHeight: 400,
frame: false,
webPreferences: {
nodeIntegration: true,
backgroundThrottling: false
}
})
// Devtools
this.win.webContents.openDevTools()
// Load main window content
this.win.loadURL(`file://${__dirname}/index.html`)
// Handle window closed
this.win.on('closed', () => {
this.win = null
})
}
我也试过:
main.js:
app.on('ready', () => {
mainWindow.createWindow(),
mainWindow.win.webContents.send('app-version', appVersion),
Menu.setApplicationMenu(mainMenu)
})
renderer.js:
console.log("Trying")
ipcRenderer.on('app-version', (args) => {
console.log(`Node version is ${args}`)
})
出于某种原因,我写的 ipcMain 应用的答案现在多次发送到渲染器并重复渲染控制台消息
Trying to send app version to renderer: 1.0.0
Trying to send app version to renderer: 1.0.0
Trying to send app version to renderer: 1.0.0
Trying to send app version to renderer: 1.0.0
Trying to send app version to renderer: 1.0.0
现在应用程序闪烁,但在 console.log
中只显示一次,我不明白为什么。
编辑
回复。
我知道 app.getVersion
我只是在使用 ENV
学习如何发送到 main。测试代码后,这种方法不起作用。
应对此:
app.on('ready', () => {
const win = mainWindow.createWindow(),
console.log(`Trying to send app version to renderer: ${appVersion}`),
win.webContents.send('app-version', appVersion),
Menu.setApplicationMenu(mainMenu)
})
抛出以下错误:
Missing initializer in const declaration
所以修改为:
app.on('ready', () => {
const win = mainWindow.createWindow()
console.log(`Trying to send app version to renderer: ${appVersion}`)
win.webContents.send('app-version', appVersion)
Menu.setApplicationMenu(mainMenu)
})
但是在 exports.createWindow
末尾添加 return 时会抛出此错误:
win is not defined
在 exports.createWindow
之前添加 let.win
不会抛出代码,但不会发送任何内容。
Electron Fiddle
index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Electron learning</title>
<!-- CSS Bootstrap -->
<!-- <link rel="stylesheet" href="../node_modules/bootstrap/dist/css/bootstrap.css"> -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<!--
Font Awesome
https://fontawesome.com/v4.7.0/cheatsheet/
-->
<!-- <link rel="stylesheet" href="../node_modules/font-awesome/css/font-awesome.css"> -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<!-- Custom CSS -->
<style>
body {
-webkit-app-region: drag;
}
footer {
position: fixed;
bottom: 0;
width: 100%;
}
#close_app,
#site {
cursor: pointer;
}
</style>
</head>
<body class="d-flex flex-column h-100">
<header>
<nav class="navbar navbar-expand navbar-dark fixed-top bg-dark">
<a class="navbar-brand text-white">Foobar</a>
<div class="collapse navbar-collapse justify-content-between">
<div class="navbar-nav">
<a id="site" class="nav-link"><small><u id="application"></u></small></a>
</div>
<div class="navbar-nav">
<a id="close_app" class="nav-item nav-link"><i class="fa fa-times-circle"></i></a>
</div>
</div>
</nav>
</header>
<main role="main" class="flex-shrink-0">
<div class="container">
<h1>Hello World!</h1>
<!-- All of the Node.js APIs are available in this renderer process. -->
We are using Node.js <script>document.write(process.versions.node)</script>,
Chromium <script>document.write(process.versions.chrome)</script>,
and Electron <script>document.write(process.versions.electron)</script>.
Electron app version <script>document.write(process.versions.electron)</script>.
</div>
<p id="testSender"></p>
</main>
<footer class="footer mt-auto py-3 ">
<div class="container">
<span class="text-muted">Place sticky footer content here.</span>
</div>
</footer>
<script>
// jQuery
// window.jQuery = window.$ = $ = require('jquery')
// You can also require other files to run in this process
require('./renderer.js')
</script>
<!-- <script src="../node_modules/jquery/dist/jquery.min.js"></script> -->
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<!-- <script src="../node_modules/bootstrap/dist/js/bootstrap.min.js"></script> -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
</body>
</html>
main.js:
'use strict'
// Modules to control application life and create native browser window
const { app, ipcMain, BrowserWindow, Menu } = require('electron')
const testMainSend = `Trying to send something to renderer`
let mainWindow
// Window state keeper
const windowStateKeeper = require('electron-window-state')
// export mainWindow
function createWindow () {
let winState = windowStateKeeper({
defaultWidth: 400,
defaultHeight: 400
})
// BrowserWindow options
// https://electronjs.org/docs/api/browser-window#new-browserwindowoptions
const win = new BrowserWindow({
width: winState.width,
height: winState.Height,
x: winState.x,
y: winState.y,
minWidth: 400,
minHeight: 400,
frame: false,
webPreferences: {
nodeIntegration: true,
backgroundThrottling: false
}
})
winState.manage(win)
// Devtools
win.webContents.openDevTools()
// Load main window content
win.loadURL(`file://${__dirname}/index.html`)
// Handle window closed
win.on('closed', () => {
this.win = null
})
return win
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', () => {
createWindow()
// 1st attempt
// webContents.send('misc-sender', testMainSend)
// 2nd attempt
// const win = createWindow()
// win.webContents.send('misc-sender', testMainSend)
// 3rd attempt
const win = createWindow()
win.webContents.on('dom-ready', () => {
console.log(`Trying to send renderer: ${testMainSend}`)
mainWindow.win.webContents.send('misc-sender', testMainSend)
})
})
// Quit when all windows are closed.
app.on('window-all-closed', () => {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
})
// Close application from button
ipcMain.on('closing-app', () => {
app.quit()
console.log('Closed app from font awesome link')
})
renderer.js:
// This file is required by the index.html file and will
// be executed in the renderer process for that window.
// All of the Node.js APIs are available in this process.
const { ipcRenderer, shell } = require('electron')
const appVersion = require('electron').remote.app.getVersion()
// Devtron
// require('devtron').install()
// Close App
const closeApp = document.getElementById('close_app')
closeApp.addEventListener('click', () => {
ipcRenderer.send('closing-app')
})
// received from ipcMain test
ipcRenderer.on('misc-sender', (event, args) => {
appendTest = document.getElementById('testSender')
appendTest.innerHTML += args
})
// Getting version
const appVersioning = document.getElementById('application')
appVersioning.innerHTML = appVersion
// Open site
const homeURL = document.getElementById('site')
homeURL.addEventListener('click', (e) => {
e.preventDefault
shell.openExternal("https://www.google.com/")
})
经过多次搜索和尝试,我想我终于想出了如何将我的应用程序版本从 package.json 发送到 main,然后再发送到渲染器。我的问题出在我的 app.on
上,我丢失了 dom-ready
,这在阅读 :
后有所帮助
main.js:
const appVersion = process.env.npm_package_version
app.on('ready', () => {
mainWindow.createWindow()
Menu.setApplicationMenu(mainMenu)
// Send version to renderer
mainWindow.win.webContents.on('dom-ready', () => {
console.log(`Trying to send app version to renderer: ${appVersion}`)
mainWindow.win.webContents.send('app-version', appVersion)
})
})
renderer.js:
ipcRenderer.on('app-version', (event, args) => {
const appVersion = document.getElementById('app_version')
console.log(`Node version is ${args}`)
appVersion.innerHTML += args
})
index.html:
<div id="app_version"></div>
可能有更好的方法,但经过进一步研究后我读到:
- Electron - How to know when renderer window is ready
dom-ready
from instance-events
这行得通,但接下来的步骤是查看拉动 process.env
是否是一种良好的安全做法。如果存在,我确实希望看到一些关于可能的更好方法的其他答案。
在回答您的问题之前,查看您发送给渲染器的消息(如果您想做的是将您的应用程序版本发送给渲染进程),可以使用 app.getVersion
完成。在您的主进程中,您必须使用 app.setVersion("1.0")
设置应用程序版本,然后在您的渲染进程中,您必须这样做
const { remote: { app } } = require("electron");
app.getVersion();
对于你的实际问题 mainWindow.createWindow()
需要 return BrowserWindow
的一个实例(查看你的代码你没有 returning 它而且你没有阅读您在 mainWindow.js
上设置的 win
属性 对象)。如果您想在问题中坚持使用当前代码,则必须这样做
mainWindow.win.webContents.send(...)
或者你应该从
mainWindow.js
// Modules
const { BrowserWindow } = require('electron')
// export mainWindow
exports.createWindow = () => {
// BrowserWindow options
// https://electronjs.org/docs/api/browser-window#new-browserwindowoptions
const win = new BrowserWindow({
minWidth: 400,
minHeight: 400,
frame: false,
webPreferences: {
nodeIntegration: true,
backgroundThrottling: false
}
})
// Devtools
win.webContents.openDevTools()
// Load main window content
win.loadURL(`file://${__dirname}/index.html`)
// Handle window closed
win.on('closed', () => {
this.win = null
})
return win;
}
main.js
const { app, ipcMain, Menu } = require('electron')
const appVersion = process.env.npm_package_version
const mainWindow = require('./renderer/mainWindow')
app.on('ready', () => {
const win = mainWindow.createWindow(),
console.log(`Trying to send app version to renderer: ${appVersion}`),
win.webContents.send('app-version', appVersion),
Menu.setApplicationMenu(mainMenu)
})
电子新手 我已经弄清楚如何从 Renderer 发送到 Main 但我正在努力学习如何去从 Main 到 Renderer。在我的研究中,我读到:
IPC send from main process to renderer 并尝试过:
main.js:
const { app, ipcMain, Menu } = require('electron')
const appVersion = process.env.npm_package_version
const mainWindow = require('./renderer/mainWindow')
app.on('ready', () => {
mainWindow.createWindow(),
console.log(`Trying to send app version to renderer: ${appVersion}`),
mainWindow.webContents.send('app-version', appVersion),
Menu.setApplicationMenu(mainMenu)
})
但我收到以下错误:
Uncaught Exception TypeError Cannot read property 'send' of undefined
阅读“Send sync message from IpcMain to IpcRenderer - Electron”后我尝试了:
ipcMain.on('app-version', (event) => {
console.log(`Sent: ${appVersion}`)
event.sender.send(appVersion)
}),
但没有任何反应或出现错误。我的renderer.js:
const { ipcRenderer } = require('electron')
ipcRenderer.on('app-version', (event, res) => {
console.log(res)
})
为什么我的 ipcMain 没有发送到我的 ipcRenderer?
编辑:
mainWindow.js:
// Modules
const { BrowserWindow } = require('electron')
// export mainWindow
exports.createWindow = () => {
// BrowserWindow options
// https://electronjs.org/docs/api/browser-window#new-browserwindowoptions
this.win = new BrowserWindow({
minWidth: 400,
minHeight: 400,
frame: false,
webPreferences: {
nodeIntegration: true,
backgroundThrottling: false
}
})
// Devtools
this.win.webContents.openDevTools()
// Load main window content
this.win.loadURL(`file://${__dirname}/index.html`)
// Handle window closed
this.win.on('closed', () => {
this.win = null
})
}
我也试过:
main.js:
app.on('ready', () => {
mainWindow.createWindow(),
mainWindow.win.webContents.send('app-version', appVersion),
Menu.setApplicationMenu(mainMenu)
})
renderer.js:
console.log("Trying")
ipcRenderer.on('app-version', (args) => {
console.log(`Node version is ${args}`)
})
出于某种原因,我写的 ipcMain 应用的答案现在多次发送到渲染器并重复渲染控制台消息
Trying to send app version to renderer: 1.0.0
Trying to send app version to renderer: 1.0.0
Trying to send app version to renderer: 1.0.0
Trying to send app version to renderer: 1.0.0
Trying to send app version to renderer: 1.0.0
现在应用程序闪烁,但在 console.log
中只显示一次,我不明白为什么。
编辑
回复
我知道 app.getVersion
我只是在使用 ENV
学习如何发送到 main。测试代码后,这种方法不起作用。
应对此:
app.on('ready', () => {
const win = mainWindow.createWindow(),
console.log(`Trying to send app version to renderer: ${appVersion}`),
win.webContents.send('app-version', appVersion),
Menu.setApplicationMenu(mainMenu)
})
抛出以下错误:
Missing initializer in const declaration
所以修改为:
app.on('ready', () => {
const win = mainWindow.createWindow()
console.log(`Trying to send app version to renderer: ${appVersion}`)
win.webContents.send('app-version', appVersion)
Menu.setApplicationMenu(mainMenu)
})
但是在 exports.createWindow
末尾添加 return 时会抛出此错误:
win is not defined
在 exports.createWindow
之前添加 let.win
不会抛出代码,但不会发送任何内容。
Electron Fiddle
index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Electron learning</title>
<!-- CSS Bootstrap -->
<!-- <link rel="stylesheet" href="../node_modules/bootstrap/dist/css/bootstrap.css"> -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<!--
Font Awesome
https://fontawesome.com/v4.7.0/cheatsheet/
-->
<!-- <link rel="stylesheet" href="../node_modules/font-awesome/css/font-awesome.css"> -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<!-- Custom CSS -->
<style>
body {
-webkit-app-region: drag;
}
footer {
position: fixed;
bottom: 0;
width: 100%;
}
#close_app,
#site {
cursor: pointer;
}
</style>
</head>
<body class="d-flex flex-column h-100">
<header>
<nav class="navbar navbar-expand navbar-dark fixed-top bg-dark">
<a class="navbar-brand text-white">Foobar</a>
<div class="collapse navbar-collapse justify-content-between">
<div class="navbar-nav">
<a id="site" class="nav-link"><small><u id="application"></u></small></a>
</div>
<div class="navbar-nav">
<a id="close_app" class="nav-item nav-link"><i class="fa fa-times-circle"></i></a>
</div>
</div>
</nav>
</header>
<main role="main" class="flex-shrink-0">
<div class="container">
<h1>Hello World!</h1>
<!-- All of the Node.js APIs are available in this renderer process. -->
We are using Node.js <script>document.write(process.versions.node)</script>,
Chromium <script>document.write(process.versions.chrome)</script>,
and Electron <script>document.write(process.versions.electron)</script>.
Electron app version <script>document.write(process.versions.electron)</script>.
</div>
<p id="testSender"></p>
</main>
<footer class="footer mt-auto py-3 ">
<div class="container">
<span class="text-muted">Place sticky footer content here.</span>
</div>
</footer>
<script>
// jQuery
// window.jQuery = window.$ = $ = require('jquery')
// You can also require other files to run in this process
require('./renderer.js')
</script>
<!-- <script src="../node_modules/jquery/dist/jquery.min.js"></script> -->
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<!-- <script src="../node_modules/bootstrap/dist/js/bootstrap.min.js"></script> -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
</body>
</html>
main.js:
'use strict'
// Modules to control application life and create native browser window
const { app, ipcMain, BrowserWindow, Menu } = require('electron')
const testMainSend = `Trying to send something to renderer`
let mainWindow
// Window state keeper
const windowStateKeeper = require('electron-window-state')
// export mainWindow
function createWindow () {
let winState = windowStateKeeper({
defaultWidth: 400,
defaultHeight: 400
})
// BrowserWindow options
// https://electronjs.org/docs/api/browser-window#new-browserwindowoptions
const win = new BrowserWindow({
width: winState.width,
height: winState.Height,
x: winState.x,
y: winState.y,
minWidth: 400,
minHeight: 400,
frame: false,
webPreferences: {
nodeIntegration: true,
backgroundThrottling: false
}
})
winState.manage(win)
// Devtools
win.webContents.openDevTools()
// Load main window content
win.loadURL(`file://${__dirname}/index.html`)
// Handle window closed
win.on('closed', () => {
this.win = null
})
return win
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', () => {
createWindow()
// 1st attempt
// webContents.send('misc-sender', testMainSend)
// 2nd attempt
// const win = createWindow()
// win.webContents.send('misc-sender', testMainSend)
// 3rd attempt
const win = createWindow()
win.webContents.on('dom-ready', () => {
console.log(`Trying to send renderer: ${testMainSend}`)
mainWindow.win.webContents.send('misc-sender', testMainSend)
})
})
// Quit when all windows are closed.
app.on('window-all-closed', () => {
// On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
})
// Close application from button
ipcMain.on('closing-app', () => {
app.quit()
console.log('Closed app from font awesome link')
})
renderer.js:
// This file is required by the index.html file and will
// be executed in the renderer process for that window.
// All of the Node.js APIs are available in this process.
const { ipcRenderer, shell } = require('electron')
const appVersion = require('electron').remote.app.getVersion()
// Devtron
// require('devtron').install()
// Close App
const closeApp = document.getElementById('close_app')
closeApp.addEventListener('click', () => {
ipcRenderer.send('closing-app')
})
// received from ipcMain test
ipcRenderer.on('misc-sender', (event, args) => {
appendTest = document.getElementById('testSender')
appendTest.innerHTML += args
})
// Getting version
const appVersioning = document.getElementById('application')
appVersioning.innerHTML = appVersion
// Open site
const homeURL = document.getElementById('site')
homeURL.addEventListener('click', (e) => {
e.preventDefault
shell.openExternal("https://www.google.com/")
})
经过多次搜索和尝试,我想我终于想出了如何将我的应用程序版本从 package.json 发送到 main,然后再发送到渲染器。我的问题出在我的 app.on
上,我丢失了 dom-ready
,这在阅读
main.js:
const appVersion = process.env.npm_package_version
app.on('ready', () => {
mainWindow.createWindow()
Menu.setApplicationMenu(mainMenu)
// Send version to renderer
mainWindow.win.webContents.on('dom-ready', () => {
console.log(`Trying to send app version to renderer: ${appVersion}`)
mainWindow.win.webContents.send('app-version', appVersion)
})
})
renderer.js:
ipcRenderer.on('app-version', (event, args) => {
const appVersion = document.getElementById('app_version')
console.log(`Node version is ${args}`)
appVersion.innerHTML += args
})
index.html:
<div id="app_version"></div>
可能有更好的方法,但经过进一步研究后我读到:
- Electron - How to know when renderer window is ready
dom-ready
frominstance-events
这行得通,但接下来的步骤是查看拉动 process.env
是否是一种良好的安全做法。如果存在,我确实希望看到一些关于可能的更好方法的其他答案。
在回答您的问题之前,查看您发送给渲染器的消息(如果您想做的是将您的应用程序版本发送给渲染进程),可以使用 app.getVersion
完成。在您的主进程中,您必须使用 app.setVersion("1.0")
设置应用程序版本,然后在您的渲染进程中,您必须这样做
const { remote: { app } } = require("electron");
app.getVersion();
对于你的实际问题 mainWindow.createWindow()
需要 return BrowserWindow
的一个实例(查看你的代码你没有 returning 它而且你没有阅读您在 mainWindow.js
上设置的 win
属性 对象)。如果您想在问题中坚持使用当前代码,则必须这样做
mainWindow.win.webContents.send(...)
或者你应该从
mainWindow.js
// Modules
const { BrowserWindow } = require('electron')
// export mainWindow
exports.createWindow = () => {
// BrowserWindow options
// https://electronjs.org/docs/api/browser-window#new-browserwindowoptions
const win = new BrowserWindow({
minWidth: 400,
minHeight: 400,
frame: false,
webPreferences: {
nodeIntegration: true,
backgroundThrottling: false
}
})
// Devtools
win.webContents.openDevTools()
// Load main window content
win.loadURL(`file://${__dirname}/index.html`)
// Handle window closed
win.on('closed', () => {
this.win = null
})
return win;
}
main.js
const { app, ipcMain, Menu } = require('electron')
const appVersion = process.env.npm_package_version
const mainWindow = require('./renderer/mainWindow')
app.on('ready', () => {
const win = mainWindow.createWindow(),
console.log(`Trying to send app version to renderer: ${appVersion}`),
win.webContents.send('app-version', appVersion),
Menu.setApplicationMenu(mainMenu)
})