5

I'm trying to find a way to return a python dictionary from a PySide2.QtCore.Slot.

main.py

import sys
from PySide2.QtCore import QObject, Slot
from PySide2.QtGui import QGuiApplication, QQmlApplicationEngine

class Backend(QObject):  
    def __init__(self, parent=None):
        return super().__init(parent)

    @Slot(result=QObject)
    def get_data(self):
        data = {}
        data["info1"] = "some information"
        data["info2"] = "some  more information"
        data["info3"] = 42
        return data

if __name__ == '__main':
    BACKEND = Backend()
    APP = QGuiApplication(sys.argv)
    ENGINE = QQmlApplicationEngine(APP)
    ENGINE.rootContext().setContextProperty('backend', BACKEND)
    ENGINE.load("main.qml")
    sys.exit(APP.exec_())

main.qml:

import QtQuick 2.4
import QtQuick.Controls 1.4

ApplicationWindow {
 id: root
 width: 640
 height: 480
 visible: true
 color: "#F0F0F0"
 title: qsTr("Test")

 Text {
     anchors.centerIn: parent
     text: backend.get_data()["info1"]
 }
} 

I think it is somehow done in QAbstractItemModel.roleNames() as it returns a QHash<int, QByteArray>?

If it doesn't work like this, can anyone please support me with "the correct way" of exchanging inforamtion between the python backend and the QML frontend?

Thanks in advance :)

Stephan
  • 143
  • 1
  • 8

1 Answers1

5

The basic types of python when they are exported to QML are converted to their corresponding type since they are supported, but for a Slot() to return something the data type must be indicated through the result parameter, in this QVariant as a string.

Example:

main.py

from PySide2 import QtCore, QtGui, QtQml


class Helper(QtCore.QObject):
    @QtCore.Slot(result='QVariant')
    def foo(self):
        return {"a": 1, "b": 2}


if __name__ == '__main__':
    import sys

    app = QtGui.QGuiApplication(sys.argv)

    engine = QtQml.QQmlApplicationEngine()
    helper = Helper()
    engine.rootContext().setContextProperty("helper", helper)
    engine.load(QtCore.QUrl.fromLocalFile('main.qml'))
    if not engine.rootObjects():
        sys.exit(-1)
    sys.exit(app.exec_())

main.qml

import QtQuick 2.9
import QtQuick.Controls 2.4

ApplicationWindow {
    visible: true
    Component.onCompleted: { 
        var data = helper.foo()
        for(var key in data){
            var value = data[key]
            console.log(key, ": ", value)
        }
    }
}

Output:

qml: a :  1
qml: b :  2
Community
  • 1
  • 1
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • 2
    thank you, this just works like expected! :) can you please tell me were to find these information? – Stephan Oct 02 '18 at 09:55
  • @Stephan It's a secret, like the rest of QT features and how to use them – Bersan Feb 25 '22 at 12:57
  • @Bersan No, it's not a secret. What happens is that pyside doesn't know how to handle python dictionaries so a generic way to send them to qml is to use QVariant which will try to deduce the type of javascript object that is best suited. Probably pyside2 can be improved so that it deduces these cases (perhaps it already does since I haven't checked the changes for a few months) – eyllanesc Feb 25 '22 at 14:50
  • @Bersan The point is that if you don't have minimal knowledge of how shiboken works (limitations) then everything will seem like a secret. – eyllanesc Feb 25 '22 at 14:52