Излучение QStandardItemModel из серверной части Python приводит к «неопределенному» объекту QML

#python #qt #qml #pyside2 #qstandarditemmodel

Вопрос:

Я пытаюсь передать объект QStandardItemModel в QML через соединение с свойством ContextProperty, содержащим серверную часть, которая генерирует эту модель на основе нажатия кнопки, но, хотя модель правильно создана в Python, похоже, она не может быть загружена QML. На самом деле приложение, над которым я работаю, более сложное, но я включаю минимальный пример, который повторяет ошибку, которую я получаю. В основном, когда приходит время установить модель, которая передается в QML через сигнал, я получаю ошибку: Невозможно назначить [неопределенный] QAbstractItemModel*

Я знаю, что такой вопрос, вероятно, задавался раньше, и я нашел другие связанные с этим вопросы, но их решения были очень похожи на то, что я реализовал, поэтому я не вижу, где именно происходит ошибка.

Во-первых, приложение QML представляет собой простое окно с кнопкой и видом дерева, которое начинается с «нулевой» модели при запуске приложения. Как только кнопка нажата, она запускает слот («trigger_signal_send») в бэкэнде, который создает модель и выдает сигнал, содержащий эту модель. Файл QML также имеет объект подключения, который прослушивает излучаемый сигнал от «серверной части» и обновляет модель в виде дерева. Обратите внимание, что я включаю только соответствующие строки (такие вещи, как якоря и графические свойства, были опущены).

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
Here is where I define the Backend class, with the relevant Slot that generates and emits the model when the button is clicked, and where I connect my Backend object to QML via the ContextProperty.

 # 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 для типа QStandardItemModel и вернуть модель непосредственно из этого слота, но я получаю ошибку на уровне QML: Неизвестный метод тип возврата: QStandardItemModel*. Это было моим обоснованием для изменения возвращаемого значения на » Нет » и для того, чтобы просто выдать эту модель в качестве сигнала. Я также попытался изменить функцию «setModel» в QML, чтобы просто напрямую ссылаться на атрибут TreeView.model, но я получаю исходную ошибку.

Я знаю, что модель создана правильно и имеет правильный тип, потому что, если я создам другой слот непосредственно в серверном классе, который будет печатать текст первого элемента при отправке «sendSignal», все будет работать правильно.

Кроме того, при настройке первой строки «onSendSignal» для регистрации ввода этой функции в ней указано «не определено», поэтому проблема заключается в том, когда sendSignal.emit(модель) вызывается в серверной части и когда onSendSignal(модель) вызывается в блоке Соединений моего файла .qml.

Я потратил много времени, играя с различными решениями, но, похоже, не могу понять, что теряется между этими двумя вызовами функций. Любая помощь будет очень признательна!

Комментарии:

1. Я отредактировал вопрос, чтобы включить код в виде текста. Я также сохраняю изображения, потому что гораздо легче увидеть, какие части на самом деле имеют отношение к вопросу.

2. @adouv нет, они только запутывают вопрос, пожалуйста, отредактируйте сообщение, удалите изображения и просмотрите вопрос, чтобы код был помещен в правильный контекст. Если вы хотите специально указать раздел кода, то вы можете использовать комментарии, но, судя по внешнему виду вашего кода, это не обязательно.

3. Я отредактировал его еще раз, чтобы удалить изображения и сохранить код в виде текста, если это сделает его менее запутанным.

Ответ №1:

Что происходит, так это то, что 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
    }
}
 

Комментарии:

1. Вау. Я потратил часы, пытаясь решить эту проблему, и перепробовал дюжину разных вещей, но мне не пришло в голову просто установить сигнатуру сигнала для QObject. Теперь все имеет гораздо больше смысла. Огромное вам спасибо за ответ и за то, как быстро вы смогли мне помочь. Очень признателен!