关闭模态窗口后,为什么电子父窗口仍然被阻止?

时间:2017-08-02 21:16:30

标签: typescript dialog electron

  • 电子版:1.7.2
  • 操作系统:Windows 10

预期行为

鼠标控制返回到父窗口。

实际行为

父窗口的鼠标输入将永久阻止。

如何重现

主应用程序的渲染器过程中对话框管理器的示例代码:

class DialogManager {
    private _dialogWindow: Electron.BrowserWindow | null = null;
    private _finalizing: boolean = false;
    private _dialogResultCompletion: q.Deferred<any> = null;

    /**
     * Entry point.
     *
     * @param args Arguments to be passed to the dialog.
     */
    public getDialogResult(args: any): Promise<any> {
        try {
            this.openDialog(args);
        } catch (error) {
            return q.reject(error);
        }

        this._dialogResultCompletion = q.defer<any>();

        return this._dialogResultCompletion.promise;
    }

   private openDialog(id: string, args: any): void {
        if (this.isDialogOpen()) {
            throw new Error("A dialog is already open. Make sure you're not opening a dialog from another dialog and that all other dialogs are closed.");
        }

        this._finalizing = false;

        this._dialogWindow = new remote.BrowserWindow({
            frame: true,
            center: true,
            height: 500,
            width: 500,
            modal: true,
            parent: remote.BrowserWindow.getFocusedWindow(),
            resizable: false,
            show: false,
            skipTaskbar: true,
            useContentSize: true
        });

        let onReady = () => {
            if (!!this._dialogWindow) {
                console.warn("Dialog is now ready");
                // Remove when done.
                this._dialogWindow.show();
                this._dialogWindow.webContents.send("dialog-init", { /* initialization parameters */ });
            }
        };

        let onInit = (e, error) => {
            if (!!error) {
                this.finalize(error, undefined);
                this._dialogResultCompletion.reject(error);
            } else {
                console.warn("Dialog is now initialized");

                this._dialogWindow.show();
            }
        };

        let onFinalize = (e, error, result) => {
            this._finalizing = true;

            if (!!this._dialogWindow) {
                this._dialogWindow.close();
            }

            this.finalize(error, result);
        }

        let onCloseOrCrash = (e, error, result) => {
            if (!this._finalizing) {
                this.finalize(error, result);
            }
            this._dialogWindow = null;
        }

        this._dialogWindow.setMenuBarVisibility(false);
        this._dialogWindow.loadURL("http://path/to/my/dialog.html");

        this._dialogWindow.once("ready-to-show", onReady);
        remote.ipcMain.once("did-dialog-init", onInit);
        remote.ipcMain.once("dialog-finalize", onFinalize);

        // Handle when the user force closes the window (such as clicking the X in Windows)
        this._dialogWindow.once("closed", onCloseOrCrash);

        // Handle the possibility of the dialog process crashing
        this._dialogWindow.webContents.once("crashed", (e) => { onCloseOrCrash(e, "The dialog renderer process crashed", undefined); });
    }

    private finalize(error: any | undefined, result: any | undefined) {
        if (!!error) {
            console.warn("Dialog is now finalizing with an error");
            this._dialogResultCompletion.reject(error);
        } else {
            console.warn("Dialog is now finalizing with a result");
            this._dialogResultCompletion.resolve(result);
        }
    }

    private isDialogOpen(): boolean {
        return !!this._dialogWindow;
    }
}

let instance = new DialogManager();

export default instance;

对话框渲染器进程的示例代码(HTML文件需要此文件):

// Initially show only the default dialog panel
$(".dialog-panel").hide();
$("#default-panel").show();

$(document)
    .keyup((e) => {
        if (e.keyCode === KeyCodes.Esc) {
            ipcRenderer.send("dialog-finalize", undefined, null);
        }
    })
    .ready(() => {
        ipcRenderer.send("dialog-ready");
    });

ipcRenderer.once("dialog-init", (e, message) => {
    try {
        // A Knockout view model object is created based on the arguments passed from the dialog manager
        let viewModel: any;

        // Initialization...

        viewModel.currentPanel.subscribe((result) => {
            $(".dialog-panel").hide();
            $("#" + result).show().focus();
        });

        // We subscribe to the `dialogResult` observable so that we may
        // automatically close the dialog when its value is set.
        viewModel.dialogResult.subscribe((result) => {
            ipcRenderer.send("dialog-finalize", undefined, result);
        });

        ko.applyBindings(viewModel);
    } catch (error) {
        ipcRenderer.send("dialog-finalize", error.message);
    }
});

(<any>process).on("unhandledException", (err) => {
    ipcRenderer.send("dialog-finalize", err.message);
});

单步执行上面的代码,按照所有预期的代码路径打开和关闭对话框窗口。但是在关闭对话框窗口并且引用设置为null后,鼠标控件不会返回到父窗口。

我没有做错什么,是吗?

我不时注意到_dialogWindow_finalizing并不总是我所期望的那样。在我设置之前,有时_finalizing已设置为true。关闭时{I} _dialogWindow有时{I} null

1 个答案:

答案 0 :(得分:0)

  

我没有做错事,是吗?

不,你做错了什么。我认为这就像Electron悲伤地工作一样。

要解决此问题,您只需调用.focus()函数即可专注于父窗口。

这样的事情:

this._parentWindow.focus();

Ref.