如何使用 HTML 按钮关闭应用程序

How To Close Application Using HTML Button

在我的 PyQt5 浏览器中 window 我加载了 HTML 和 JavaScript。我在 HTML 中添加了一个按钮,该按钮应该使用 vanilla JavaScript 关闭 Python-Application。这是我的 Python 代码,它生成 window 并加载 HTML-File:

import sys
import os
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebEngineWidgets import *


class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.browser = QWebEngineView()
        config_name = 'data_files/init.html'
        if getattr(sys, 'frozen', False):
            application_path = os.path.dirname(sys.executable)
        elif __file__:
            application_path = os.path.dirname(__file__)
        config_path = os.path.join(application_path, config_name)
        self.browser.load(QUrl().fromLocalFile(config_path))
        self.setCentralWidget(self.browser)
        self.showMaximized()


app = QApplication(sys.argv)
QApplication.setApplicationName('v0.1')
window = MainWindow()
app.exec_()

在我的 HTML 中我有这个:

<button onclick="exitApplication()">Exit</button>

<script>
    function exitApplication() {
        // How can I tell Python to call self.close() ??
    }
</script>

正如我所说,我想使用 HTML 中的按钮关闭应用程序。我查看了各种来源,但我从来没有找到任何对我有帮助或太令人困惑的东西。

如何在调用 exitApplication()-函数时关闭应用程序?

首先要知道关闭window和退出应用是不一样的,如果你只有一个window和属性 quitOnLastWindowClosed in True那么它们是等价的,但总的来说是不一样的。

QtWebChannel:

import sys
import os
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QCoreApplication, QObject, QUrl
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtWebChannel import QWebChannel

application_path = (
    os.path.dirname(sys.executable)
    if getattr(sys, "frozen", False)
    else os.path.dirname(__file__)
)


class Bridge(QObject):
    request_closed = pyqtSignal()

    @pyqtSlot()
    def quit(self):
        QCoreApplication.quit()

    @pyqtSlot()
    def close(self):
        self.request_closed.emit()


class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.browser = QWebEngineView()

        self.bridge = Bridge()

        self.bridge.request_closed.connect(self.close)

        self.channel = QWebChannel()
        self.channel.registerObject("bridge", self.bridge)
        self.browser.page().setWebChannel(self.channel)

        config_name = "data_files/init.html"
        config_path = os.path.join(application_path, config_name)
        self.browser.load(QUrl.fromLocalFile(config_path))
        self.setCentralWidget(self.browser)
        self.showMaximized()


if __name__ == "__main__":

    app = QApplication(sys.argv)
    QApplication.setApplicationName("v0.1")
    window = MainWindow()
    app.exec_()
<!DOCTYPE html>
<html>
  <head>
    <script src="qrc:///qtwebchannel/qwebchannel.js"></script>
  </head>
  <body>
    <button onclick="exitApplication()">Exit</button>

    <script>
      var bridge = null;
      function exitApplication() {
        bridge.quit();
        // bridge.close();
      }
      if (typeof QWebChannel !== "undefined") {
        new QWebChannel(qt.webChannelTransport, function (channel) {
          bridge = channel.objects.bridge;
        });
      }
    </script>
  </body>
</html>

QWebEngineUrlSchemeHandler:

import sys
import os
from PyQt5.QtCore import QCoreApplication, QUrl
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.QtWebEngineCore import (
    QWebEngineUrlScheme,
    QWebEngineUrlSchemeHandler,
    QWebEngineUrlRequestJob,
)
from PyQt5.QtWebEngineWidgets import QWebEngineView


application_path = (
    os.path.dirname(sys.executable)
    if getattr(sys, "frozen", False)
    else os.path.dirname(__file__)
)


class QtSchemeHandler(QWebEngineUrlSchemeHandler):
    def requestStarted(self, job):
        if job.requestMethod() == b"POST" and job.requestUrl() == QUrl(
            "qt://commands/quit"
        ):
            QCoreApplication.quit()
            return
        job.fail(QWebEngineUrlRequestJob.RequestFailed)


class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.browser = QWebEngineView()
        self.scheme_handler = QtSchemeHandler()
        self.browser.page().profile().installUrlSchemeHandler(
            b"qt", self.scheme_handler
        )

        config_name = "data_files/init.html"
        config_path = os.path.join(application_path, config_name)
        self.browser.load(QUrl.fromLocalFile(config_path))
        self.setCentralWidget(self.browser)
        self.showMaximized()


if __name__ == "__main__":

    scheme = QWebEngineUrlScheme(b"qt")
    scheme.setFlags(QWebEngineUrlScheme.CorsEnabled)
    QWebEngineUrlScheme.registerScheme(scheme)

    app = QApplication(sys.argv)
    QApplication.setApplicationName("v0.1")
    window = MainWindow()
    app.exec_()
<!DOCTYPE html>
<html>
  <body>
    <button onclick="exitApplication()">Exit</button>

    <script>
      function exitApplication() {
        const xhr = new XMLHttpRequest();
        xhr.open("POST", "qt://commands/quit", true);
        xhr.send();
      }
    </script>
  </body>
</html>