在关闭所有打开的渲染器进程的app.quit中,电子事件发射器错误

时间:2018-11-18 11:09:17

标签: node.js electron

我有一个主窗口,其中列出了所有可用的服务器以及带有服务器ID的状态按钮。按下相关状态按钮后,将打开一个信息窗口-将ID传递给信息窗口的副本,从而使状态按钮处于禁用状态。如果关闭了信息窗口,则信息窗口会将ID传递回主窗口,从而使状态按钮再次启用。为此,我使用main.js作为代理,侦听渲染器进程并在主窗口和信息窗口之间交换信息。

我想做的是列出服务器。如果它们在线,则一次从不同渲染器进程(信息窗口的实例)上的多个服务器获取一些信息。

问题是,如果主窗口关闭,我希望所有信息窗口都关闭。

// App ready
app.on('ready', ()=>{
    mainWindow = new BrowserWindow({x : 0, y : 0 , width : 500, height: 600});

    mainWindow.loadURL(url.format({
        pathname : path.join(__dirname, 'windows', 'mainWindow.html'),
        protocol : 'file',
        slashes : true
    }));

    // Close the app if main window closed
    mainWindow.on('close', (e) => {
        let openedOnes = BrowserWindow.getAllWindows();
        openedOnes.forEach(wind => {
            if(wind.hasOwnProperty('custom')){
                wind.close();
            };
        });

        app.quit();
    });
});

在创建信息窗口时,我向BrowserWindow对象添加了一个自定义字段:

BrowserWindow {
  _events:
   { blur: [Function],
     focus: [Function],
     show: [Function: visibilityChanged],
     hide: [Function: visibilityChanged],
     minimize: [Function: visibilityChanged],
     maximize: [Function: visibilityChanged],
     restore: [Function: visibilityChanged],
     close: [Function: callIntoRenderer] },
  _eventsCount: 8,
  devToolsWebContents: [Getter],
  custom: { server_id: '3' } }

因此,借助自定义字段,我可以获得所有打开的服务器信息实例。

但是当我单击关闭时,以下部分在main.js处失败;

ipcMain.on('window_closed', (e, item)=>{
    mainWindow.webContents.send('button_enable', item);
});

它会引发以下错误。

enter image description here

main.js:53是行ipcMain.on('window_closed'...。顺便说一句,如果我忽略了这一行,一切都会很好地工作。

3 个答案:

答案 0 :(得分:1)

似乎发生了什么事,您的mainWindow close处理函数被触发,告诉其他窗口关闭,然后触发了window_closed事件(我想这是您自定义的事件添加?),并在调用mainWindow.webContents.send时,mainWindow的关闭处理程序完成,窗口关闭。

在发送消息之前,只需添加isDestroyed检查,就像这样:

ipcMain.on('window_closed', (e, item)=>{
    if (mainWindow && !mainWindow.isDestroyed())
        mainWindow.webContents.send('button_enable', item);
});

您的其他选择(虽然可能不是最佳选择)是

  1. 在主窗口关闭时设置一个标志,如果window_closed处理程序看到该标志,则将其退出(如果我们要关闭所有内容,肯定没有理由发送button_enable消息)下):

let mainWindowIsClosing = false;
mainWindow.on('close', (e)=>{
    mainWindowIsClosing = true;
    ...
    wind.close();
    ...
});

ipcMain.on('window_closed', (e, item)=>{
    if (mainWindowIsClosing) return;
    mainWindow.webContents.send('button_enable', item);
});
  1. 您可以调用destroy方法而不是close来避免为子窗口触发close事件。 (尽管我相信window_closed不是电子事件,所以这取决于您如何挂钩所有内容):

mainWindow.on('close', (e)=>{
    ...
    wind.destroy();
});

答案 1 :(得分:0)

找到了以下解决方案;

mainWindow.on('close', (e)=>{
    mainWindow = null;
    try{
        let openedOnes = BrowserWindow.getAllWindows();
        openedOnes.forEach(wind=>{
            if(wind.hasOwnProperty('custom')){
                wind.close();
            };
        });

        app.quit();

    }catch(e){
        console.log(e);
    }
});

在关闭主窗口之前,我将主窗口设置为null。关闭信息窗口后,检查其是否未设置为null,向主窗口发送信息窗口已关闭且应启用其状态按钮的信息;

ipcMain.on('window_closed', (e, item)=>{
    try {
        if(mainWindow !== null){
            mainWindow.webContents.send('button_enable', item);
        }
    } catch (error) {
        console.log(error);
    }
});

答案 2 :(得分:0)

您应该像下面这样使用子级/父级BrowserWindows:https://electronjs.org/docs/api/browser-window#parent-and-child-windows

使用以下所有子窗口,您将变得更加轻松

win.getChildWindows()

https://electronjs.org/docs/api/browser-window#wingetchildwindows