QtWebKit bridge: call JavaScript functions

1.2k views Asked by At

I am writing a hybrid application with HTML interface and Python code. I can access Python functions via a shared object:

pythonPart.py:

class BO(QObject):
    def __init__(self, parent=None):
        super(BO, self).__init__(parent)

    @Slot(str)
    def doStuff(self, txt):
        print(txt)

bridgeObj = BO()

# init stuff and frame...
frame.addToJavaScriptWindowObject( 'pyBridge', bridgeObj )
frame.evaluateJavaScript('alert("Alert from Python")')
frame.evaluateJavaScript('testMe()')
frame.evaluateJavaScript('alert("Starting test");testMe();alert("Test over")')

jsPart.js:

function testMe() { alert('js function testMe called'); }

pyBridge.doStuff("bla");
testMe();

Calling Python functions from JS works, as does calling testMe from JS. Calling "standard" JS functions like alert from Python works, too.

The last two Python lines won't: evaluateJavaScript("testMe()") doesn't do anything at all. The last line executes the first alert and won't continue after that.

EDIT: I already tried having some time.sleep() between loading and calling the evaluateJavaScript and I'm loading the webpage from the local machine.

2

There are 2 answers

1
marten-de-vries On BEST ANSWER

The most likely problem is that the JavaScript just isn't loaded yet. Adding time.sleep() calls doesn't help for that, those will also block the Qt event loop from continuing, not just your Python code.

Try waiting for the page to have fully loaded instead, for example (using the loadFinished signal:

def onLoad():
    frame.evaluateJavaScript('testMe()')

frame.loadFinished.connect(onLoad)

Aditionally, for getting more debug information in situations like this, you might want to implement QtWebKit.QWebPage.javaScriptConsoleMessage.

1
ekhumoro On

There are at least two errors in the example code.

Firstly, when you add the object to the javascript window, you call it "pyBridge", but you then try to reference it in the javascript as "bridgeObj". Obviously, this will throw a ReferenceError which will prevent any further execution of the script.

Secondly, the doStuff method is missing a self argument, which will cause a TypeError to be raised by PySide.

Dealing with those two issues should be enough to fix your example code, so long as you make sure that the bridge object is added to the javacsript window before the html is loaded. This step is required if you want to reference the bridge object in top-level javascript code. However, if the bridge object is only ever referenced in function-level code, it can be safely added to the javascript window after the html has loaded.