[PyQt] PyQt5 QtWebEngine: can't block python till javascript is finished with a callback function

Daan V. daanv1987 at gmail.com
Fri May 6 10:28:19 BST 2016


When I call the runJavaScript function of QWebEnginePage with a callback I
can't block the python code on this call. I've tried sleeping, "spinning
the event loop" (Kovid Goyal -
https://riverbankcomputing.com/pipermail/pyqt/2015-January/035324.html) and
a combination of both. The example below shows how the
"call_js_with_callback" keeps waiting.

When this while loop is removed from "call_js_with_callback" the callback
actually happens. This means in an asynchronous environment this would not
be an issue, but when porting a legacy project which was not written with
asynchronous behavior in mind there is no quick way to port. Can anyone
tell me if this is correct or if I've made a mistake and/or there is a
workaround I can use?

Another interesting thing is that a callback method declared as I have it
will crash unless the @pyqtSlot() is changed in an @pyqtSlot(str) (or
something similar I assume). With @pyqtSlot() the callback will retrieve
None as parameter and a silent crash of the application happens. Maybe this
can be added to the
http://pyqt.sourceforge.net/Docs/PyQt5/api/qwebenginepage.html page or an
error message can be returned when the callback fails.

Regards and thanks in advance,

Daan Veltman

from PyQt5.Qt import *
from PyQt5.QtWebEngineWidgets import QWebEnginePage, QWebEngineScript,
QWebEngineView
from time import sleep

class WebPage(QWebEnginePage):
    javascript_is_ready = False

    @pyqtSlot()
    def html_ready(self):
        print 'html_ready'
        self.html_ready = True
        self.call_js_with_callback()

    def call_js_with_callback(self):
        print 'call_js_with_callback'
        self.runJavaScript('js_function("with_callback")', self.callback)
        while not self.javascript_is_ready:
            print 'processing events'

QApplication.instance().processEvents(QEventLoop.ExcludeUserInputEvents |
QEventLoop.ExcludeSocketNotifiers | QEventLoop.WaitForMoreEvents)
            sleep(0.5)
        print 'through with sleeping!'

    @pyqtSlot(str)
    def callback(self, none):
        print 'calling back!', none
        self.javascript_is_ready = True


app = QApplication([])
page = WebPage()
view = QWebEngineView()
view.setPage(page)
channel = QWebChannel(page)
channel.registerObject('page', page)
page.setWebChannel(channel)
view.setHtml(
            '<html>' + '\n'
            '  <body>' + '\n'
            '    <script src="
https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js"></script>'
+ '\n'
            '    <script type="text/javascript" src="
https://rawgit.com/qtproject/qtwebchannel/dev/src/webchannel/qwebchannel.js"></script>'
+ '\n'
            '    <p>Hello world!</p>' + '\n'
            '    <script type="text/javascript">' + '\n'
            '        function js_function(text) {' + '\n'
            '            alert("js_function! " + text);' + '\n'
            '            }' + '\n'
            '    </script>' + '\n'
            '    <script type="text/javascript">' + '\n'
            '        $(document).ready(function(){' + '\n'
            '            alert("document ready");' + '\n'
            '            new QWebChannel(qt.webChannelTransport, function
(channel) {' + '\n'
            '                page = channel.objects.page;' + '\n'
            '                page.html_ready();' + '\n'
            '            });' + '\n'
            '        });' + '\n'
            '    </script>' + '\n'
            '    <p>Done!</p>' + '\n'
            '  </body>' + '\n'
            '</html>')
view.show()
app.exec_()
print 'exit'
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20160506/e4cba032/attachment.html>


More information about the PyQt mailing list