从 Python 后端发出 QStandardItemModel 导致 "undefined" QML 对象

Emitting QStandardItemModel from Python backend results in "undefined" QML object

我正在尝试通过与包含后端的 ContextProperty 的连接将 QStandardItemModel 对象传递给 QML,该后端基于按钮单击生成此模型,但是虽然模型是在 Python 中正确创建的,但似乎它不能被 QML 加载。实际上,我正在处理的应用程序更为复杂,但我包含了一个最小示例,它复制了我得到的错误。基本上,当需要设置通过信号传递给 QML 的模型时,我收到错误消息:Unable to assign [undefined] to QAbstractItemModel*

我知道这种问题以前可能有人问过,我也找到了其他相关问题,但是他们的解决方案与我实现的非常相似,所以我没能确切地看到错误发生的地方。

首先,QML 应用程序是一个简单的 window,带有一个按钮和一个在应用程序启动时以“空”模型开头的 TreeView。单击按钮后,它会在后端触发创建模型的槽(“trigger_signal_send”),并发出包含该模型的信号。 QML 文件还有一个 Connection 对象,它侦听从“后端”发出的信号并更新 TreeView 中的模型。请注意,我只包括相关行(省略了锚点和图形属性等内容)。

main.qml

import QtQuick 2.14
import QtQuick.Controls 1.4
import QtQuick.Window 2.14

Window {
    id: mainWindow
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")

    property var myModel: null

    function setModel(model) {
        mainWindow.myModel = model
    }

    Rectangle {
        anchors.fill: parent
        anchors.margins: {
            top: 10
            left: 10
            right: 10
            bottom: 60
        }
        clip: true

        TreeView {
            id: treeView
            model: mainWindow.myModel
            anchors.fill: parent
        }
    }

    Button {
        id: btn
        onClicked: {
            backend.trigger_signal_send()
        }
    }

    Connections {
        id: conn
        target: backend

        function onSendModel(model) {
            mainWindow.setModel(model)
        }
    }
}

main.py 这是我定义后端 class 的地方,在单击按钮时使用相关的插槽生成和发出模型,我在这里通过 ContextProperty 将我的后端对象连接到 QML。

# This Python file uses the following encoding: utf-8
import os
from pathlib import Path
import sys

from PySide2.QtCore import QObject, Signal, Slot
from PySide2.QtGui import QGuiApplication, QStandardItemModel, QStandardItem
from PySide2.QtQml import QQmlApplicationEngine


class Backend(QObject):
    # Class attributes
    model: QStandardItemModel = QStandardItemModel()

    # Signals
    sendModel: Signal = Signal(QStandardItemModel)

    def __init__(self, *args, **kwargs):
        super(Backend, self).__init__(*args, **kwargs)
        self.sendModel.connect(self.print_model)

    @Slot()
    def print_model(self, model):
        print(model.item(0).text())
        return

    @Slot(result=None)
    def trigger_signal_send(self):
        self.model = QStandardItemModel()
        self.model.appendRow(QStandardItem('TEST ITEM'))
        self.sendModel.emit(self.model)
        return




if __name__ == "__main__":
    app = QGuiApplication(sys.argv)
    engine = QQmlApplicationEngine()

    backend = Backend()
    engine.rootContext().setContextProperty('backend', backend)

    engine.load(os.fspath(Path(__file__).resolve().parent / "main.qml"))
    if not engine.rootObjects():
        sys.exit(-1)
    sys.exit(app.exec_())

我尝试将 @Slot 装饰器中的“result”关键字设置为 QStandardItemModel 类型,并 return 直接从该槽中输入模型,但我在 QML 级别遇到错误:未知方法return类型:QStandardItemModel*。这是我将 return 值更改为 None 并仅将该模型作为信号发出的理由。我还尝试将 QML 中的“setModel”函数更改为直接引用 treeView.model 属性,但我得到了原始错误。

我知道模型创建正确,类型正确,因为如果我直接在后端创建另一个 Slot class,它将在发出“sendSignal”时打印第一项的文本, 一切正常。

此外,当设置“onSendSignal”的第一行以记录对该函数的输入时,它显示“未定义”,因此问题出在后端调用 sendSignal.emit(model) 之间以及在我的 .qml 文件的连接块中调用 onSendSignal(model) 时。

我花了很多时间尝试不同的解决方案,但我似乎无法弄清楚这两个函数调用之间丢失了什么。任何帮助将不胜感激!

QML 无法识别 QStandardItemModel 类型,导出模型时最好使用 QObject 作为签名:

# Signals
sendModel: Signal = Signal(QObject)

与 QTreeView 不同,在 TreeView 中,您必须设置每列将使用的角色:

TreeView {
    id: treeView
    model: mainWindow.myModel
    anchors.fill: parent
    TableViewColumn {
        title: "Name"
        role: "display"
        width: 300
    }
}