pythonqmlsignalspyside6

the python @QmlElement class signer data sent to qml cannot be parsed


I created a PySide6 QML project where a QmlElement class has a slot function callable from the QML interface. After invoking this slot, the class instance asynchronously emits a signal to send a text to a QML control, but unexpectedly receives an object instead. How can I resolve this issue?

  1. The main.py which contains the @QmlElement I defined:
import sys
from argparse import ArgumentParser
from pathlib import Path

from PySide6.QtCore import QObject, Signal, Slot, Property
from PySide6.QtGui import QGuiApplication
from PySide6.QtQml import QmlElement, QQmlApplicationEngine, QQmlDebuggingEnabler

QML_IMPORT_NAME = "my.ext"
QML_IMPORT_MAJOR_VERSION = 1

@QmlElement
class MyClass(QObject):
    valueChanged = Signal(str)

    @Slot()
    def setText(self):
        self.valueChanged.emit('str')


if __name__ == '__main__':



    app = QGuiApplication(sys.argv)

    engine = QQmlApplicationEngine()

    engine.addImportPath(Path(__file__).parent)

    qml_file = Path(__file__).parent / 'main.qml'

    engine.load(qml_file)

    if not engine.rootObjects():
        sys.exit(-1)

    sys.exit(app.exec())
  1. main.qml file
import QtQuick
import QtQuick.Controls
import my.ext

ApplicationWindow {
    id: appWindow

    width: 800
    height: 600
    visible: true

    title: "Application"

    Text {
        id: text
        anchors.centerIn: parent
        text: "Hello World!"
    }

    MouseArea {
        anchors.fill: parent
        onClicked: {
            myObj.setText()
        }
    }

    MyClass {
        id: myObj
        onValueChanged: {
            text.text = '' + data
            console.log("Value changed: " + data)
        }
    }
}
  1. run: shows "Hello World" result

  2. after click, it shows:

QQuickItem(0x1f5169ed150),QQuickContentItem(0x1f5169ed6c0, "ApplicationWindow")

result2


Solution

  • You are assuming that "data" is the object being sent via the signal. data is a property of ApplicationWindow:

    data : list<Object>

    The data property allows you to freely mix visual children, resources and other Windows in a Window.

    If you assign another Window to the data list, the nested window will become "transient for" the outer Window.

    If you assign an Item to the data list, it becomes a child of the Window's contentItem, so that it appears inside the window. The item's parent will be the window's contentItem, which is the root of the Item ownership tree within that Window.

    If you assign any other object type, it is added as a resource.

    It should not generally be necessary to refer to the data property, as it is the default property for Window and thus all child items are automatically assigned to this property.

    See also QWindow::transientParent().

    That's why a list of Objects is printed.

    A possible solution is to use arguments to set the name of the object being sent:

    valueChanged = Signal(str, arguments=["val"])
    

    Then:

    MyClass {
        id: myObj
        onValueChanged: {
            text.text = '' + val
            console.log("Value changed: " + val)
        }
    }