6

I'm planning on executing a javascript function from pyqt QWebEngine. I followed a example which was using a map and map bound were retrieved when a Qt application button was pushed, and wrote a small example.

html:

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
</head>

<body>

<script>
    function helloWorld(param1, param2) {
        return "Hello world " + param1 + " " + param2;
    }
</script>

</body>
</html>

Python:

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget
from PyQt5.QtWebEngineWidgets import QWebEngineView


class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.form_widget = FormWidget(self)
        _widget = QWidget()
        _layout = QVBoxLayout(_widget)
        _layout.addWidget(self.form_widget)
        self.setCentralWidget(_widget)


class FormWidget(QWidget):
    def __init__(self, parent):
        super(FormWidget, self).__init__(parent)
        self.__controls()
        self.__layout()
        self.browser.page().runJavaScript("helloWorld()", self.ready)

    def __controls(self):
        html = open('test.html', 'r').read()
        self.browser = QWebEngineView()
        self.browser.setHtml(html)

    def __layout(self):
        self.vbox = QVBoxLayout()
        self.hBox = QVBoxLayout()
        self.hBox.addWidget(self.browser)
        self.vbox.addLayout(self.hBox)
        self.setLayout(self.vbox)

    def ready(self, returnValue):
        print(returnValue)

def main():
    app = QApplication(sys.argv)
    win = MainWindow()
    win.show()
    app.exec_()


if __name__ == '__main__':
    sys.exit(main())

Nevertheless, I get the following error:

js: Uncaught ReferenceError: helloWorld is not defined
None ----> This is the return value printed at ready()

What am I missing?

1
  • Does window.helloWorld() work? Commented Aug 30, 2018 at 13:36

1 Answer 1

12

You have 2 errors:

  • You are calling the function when the page has not yet finished loading.

  • Your function needs 2 parameters, although it also works but will signal undefined.

Using the above you get the following:

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget
from PyQt5.QtWebEngineWidgets import QWebEngineView


class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.form_widget = FormWidget(self)
        _widget = QWidget()
        _layout = QVBoxLayout(_widget)
        _layout.addWidget(self.form_widget)
        self.setCentralWidget(_widget)


class FormWidget(QWidget):
    def __init__(self, parent):
        super(FormWidget, self).__init__(parent)
        self.__controls()
        self.__layout()

    def __controls(self):
        html = open('test.html', 'r').read()
        self.browser = QWebEngineView()
        self.browser.setHtml(html)
        self.browser.loadFinished.connect(self.onLoadFinished)

    def onLoadFinished(self, ok):
        if ok:
            self.browser.page().runJavaScript("helloWorld(1, \"2\")", self.ready)

    def __layout(self):
        self.vbox = QVBoxLayout()
        self.hBox = QVBoxLayout()
        self.hBox.addWidget(self.browser)
        self.vbox.addLayout(self.hBox)
        self.setLayout(self.vbox)

    def ready(self, returnValue):
        print(returnValue)

def main():
    app = QApplication(sys.argv)
    win = MainWindow()
    win.show()
    return app.exec_()


if __name__ == '__main__':
    sys.exit(main())

plus:

To visualize the output of the js console you must overwrite the javaScriptConsoleMessage method of QWebEnginePage:

...
class WebEnginePage(QWebEnginePage):
    def javaScriptConsoleMessage(self, level, message, lineNumber, sourceID):
        print("javaScriptConsoleMessage: ", level, message, lineNumber, sourceID)


class FormWidget(QWidget):
    ...
    def __controls(self):
        ...
        self.browser = QWebEngineView()
        self.browser.setPage(WebEnginePage(self.browser))
        ...

To verify this you must use console.log(...):

*.html

...
<script>
    function helloWorld(param1, param2) {
        console.log("Hello world")
        return "Hello world " + param1 + " " + param2;
    }
</script>
...

Output:

javaScriptConsoleMessage:  0 Hello world 12 data:text/html;charset=UTF-8,%3C%21DOCTYPE%20html%3E%0A%3Chtml%3E%0A%0A%3Chead%3E%0A%20%20%20%20%3Cmeta%20charset%3D%22UTF-8%22%3E%0A%3C%2Fhead%3E%0A%0A%3Cbody%3E%0A%0A%3Cscript%3E%0A%20%20%20%20function%20helloWorld%28param1%2C%20param2%29%20%7B%0A%20%20%20%20%09console.log%28%22Hello%20world%22%29%0A%20%20%20%20%20%20%20%20return%20%22Hello%20world%20%22%20%2B%20param1%20%2B%20%22%20%22%20%2B%20param2%3B%0A%20%20%20%20%7D%0A%3C%2Fscript%3E%0A%0A%3C%2Fbody%3E%0A%3C%2Fhtml%3E
Sign up to request clarification or add additional context in comments.

4 Comments

That was my first thought, and tried using time.sleep(1). Maybe It wasnt enough. Your approach is much better, I Will try It later thanks :)
@RomanRdgz never use time.sleep(...) in a GUI since that function does not pause, if it does not block the GUI preventing other tasks from being executed.
do you happen to know if js console output is somehow accesible through the QWebEngineView? Otherwise I'll need to debut the js being blind
@RomanRdgz for debugging see this answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.