PySide2 and supporting addToJavaScriptWindowObject

1.5k Views Asked by At

I am trying to port PySide application version #1 to PySide2 and struggle to find the solution for porting following code snippet:

class AppManager(QtCore.QObject):
    '''
    methods of AppObject will be available from javascript
    '''
    def __init__(self, webview):
        QtCore.QObject.__init__(self)


class WebView(QWebEngineView):
    def __init__(self, parent=None):
        QWebEngineView.__init__(self, parent)
        self.setPage(WebEnginePage(self))

    def contextMenuEvent(self, event):
        pass


class AppWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        self.view = WebView(self)
        self.page = self.view.page()
        self.app_manager = AppManager(self.view)
        self.page.mainFrame().addToJavaScriptWindowObject('app_manager', self.app_manager)
        # ERROR in above line !!!

I can't find in documentation where I have to find possible fix

1

There are 1 best solutions below

2
eyllanesc On

You have to use QWebChannel, for that you have to download qwebchannel.js (link leads to qwebchannel.js for Qt 5.12, for different versions change github branch).

In the following code I show an example:

.
├── index.html
├── main.py
└── qwebchannel.js

main.py

import sys

from PySide2 import QtCore, QtGui, QtWidgets, QtWebEngineWidgets, QtWebChannel


class WebEnginePage(QtWebEngineWidgets.QWebEnginePage):
    pass

class AppManager(QtCore.QObject):
    textChanged = QtCore.Signal(str)
    def __init__(self, webview):
        QtCore.QObject.__init__(self)
        self.m_text = ""

        timer = QtCore.QTimer(self)
        timer.timeout.connect(self.on_timeout)
        timer.start(1000)

    def on_timeout(self):
        self.text  = QtCore.QDateTime.currentDateTime().toString()

    @QtCore.Property(str, notify=textChanged)
    def text(self):
        return self.m_text

    @text.setter
    def setText(self, text):
        if self.m_text == text:
            return
        self.m_text = text
        self.textChanged.emit(self.m_text)


class WebView(QtWebEngineWidgets.QWebEngineView):
    def __init__(self, parent=None):
        QtWebEngineWidgets.QWebEngineView.__init__(self, parent)
        self.setPage(WebEnginePage(self))

    def contextMenuEvent(self, event):
        pass


class AppWindow(QtWidgets.QMainWindow):
    def __init__(self):
        QtWidgets.QMainWindow.__init__(self)
        self.view = WebView(self)
        self.page = self.view.page()
        self.app_manager = AppManager(self.view)
        channel = QtWebChannel.QWebChannel(self)
        self.page.setWebChannel(channel)
        channel.registerObject("app_manager", self.app_manager)
        self.view.load(QtCore.QUrl.fromLocalFile(QtCore.QDir.current().filePath("index.html")))
        self.setCentralWidget(self.view)

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    w = AppWindow()
    w.show()
    sys.exit(app.exec_())

index.html

<html>
<head>
    <script type="text/javascript" src="./qwebchannel.js"></script>
</head>
<header><title>This is title</title></header>
<body>

<p id="output"></p>

<script type="text/javascript">
    window.onload = function() {
        new QWebChannel(qt.webChannelTransport, function (channel) {
            window.app_manager = channel.objects.app_manager;
            console.log(app_manager);

            app_manager.textChanged.connect(function(message) {
                document.getElementById("output").innerHTML = "Received message: " + message;
            });

        });
    }
</script> 
</body>
</html>