[PyQt] How to send basic (json-expressible) objects from PyQt up to QML?

Russell Warren russ at perspexis.com
Thu Feb 2 03:31:08 GMT 2017


Sending basic javascript objects (ie: anything expressible with simple
json) down to PyQt works fantastically well with the use of
QJSValue.toVariant(), but I'm having a hard time figuring out how to do the
reverse.

What is the correct way to send arbitrarily nested, json-expressible,
objects from PyQt up to QML?

Below is a small example that demonstrates both aspects.  Push the button
and you can send an arbitrary javascript/json object down to python.  It
will translate to python perfectly.  The example then tries to send it back
to QML in a signal argument, but the result isn't quite right.

Here's the console output for the unmodified example (after button push):

Python received: [{'foo': 'bar', 'baz': 1}, [1, 2, 3]]
Emitting signal...
qml: QML received: [object Object],1,2,3

Ideally, QML should receive the same thing!

I have tried some variations of QJSValue and QVariant with no success.
What is the correct way to do this?

Here is the complete example:

#!/usr/bin/env python
import sys
from PyQt5 import QtCore, QtQml, QtQml, QtWidgets

QML = '''
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
import SignalTesting 1.0

Window {
    id: base
    visible: true
    width: 300
    height: 100

    SignalTester {
        id: st
        onTestSignal: console.log("QML received: " + testVal)
    }
    Column {
        TextInput {
            id: txtEval
            text: "[{foo: 'bar', baz: 1}, [1,2,3]]"
        }
        Button {
            text: "sendSignal"
            onClicked: st.sendSignal(eval(txtEval.text))
        }
    }
}
'''

class SignalTester(QtCore.QObject):
    testSignal = QtCore.pyqtSignal(QtCore.QVariant, arguments = ["testVal"])

    @QtCore.pyqtSlot(QtQml.QJSValue)
    def sendSignal(self, v):
        v = v.toVariant()
        print("Python received: %r" % v)
        print("Emitting signal...")
        self.testSignal.emit(v)


if __name__ == '__main__':
    qmlPath = "SignalTester.qml"
    with open(qmlPath, "w") as fp:
        fp.write(QML)
    app = QtWidgets.QApplication(sys.argv + ["-nograb"])
    QtQml.qmlRegisterType(SignalTester, "SignalTesting", 1, 0,
"SignalTester")
    engine = QtQml.QQmlApplicationEngine(qmlPath)
    sys.exit(app.exec_())
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20170201/b919c8cf/attachment-0001.html>


More information about the PyQt mailing list