#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. Теперь все имеет гораздо больше смысла. Огромное вам спасибо за ответ и за то, как быстро вы смогли мне помочь. Очень признателен!