ListView QtQuick не может стать владельцем объекта QAbstractItemModel - PullRequest
0 голосов
/ 12 сентября 2018

На основе документации Qt всякий раз, когда тип указателя QObject передается из кода C ++ в QML, с помощью метода Q_INVOKABLE , существует набор правилкоторые определяют, кто отвечает за время жизни этого указателя.Если QObject не имеет родителей, то неявно, что механизм QML отвечает за принятие владения указателем.

В моем сценарии я хочу, чтобы мой интерфейс внешнего интерфейса представлял модель списка, которая генерируется / предоставляетсяс помощью внутреннего кода C ++.Мое предположение состоит в том, что указатель будет оставаться в живых до тех пор, пока на него ссылается код QML.Приведенный ниже код показывает сокращенный тестовый пример:

Main.cpp

#include <QAbstractItemModel>
#include <QDebug>
#include <QGuiApplication>
#include <QObject>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QStringListModel>

class MyStringListModel : public QStringListModel
{
    Q_OBJECT

public:

    explicit MyStringListModel(const QStringList &strings, QObject* parent=nullptr) : QStringListModel(strings, parent)
    {
        qDebug() << "Creation";
    }

    virtual ~MyStringListModel() override
    {
        qDebug() << "Destruction";
    }
};

class Backend : public QObject
{
    Q_OBJECT

public:

    Backend(QObject* parent=nullptr) : QObject(parent)
    {

    }

    Q_INVOKABLE QAbstractItemModel* createModel() const
    {
        static const QStringList months = {
            tr("January"),
            tr("February"),
            tr("March"),
            tr("April"),
            tr("May"),
            tr("June"),
            tr("July"),
            tr("August"),
            tr("September"),
            tr("October"),
            tr("November"),
            tr("December"),
        };

        return new MyStringListModel(months);
    }
};

int main(int argc, char* argv[])
{
    QGuiApplication application(argc, argv);

    qmlRegisterType<QAbstractItemModel>();

    Backend backend;

    QQmlApplicationEngine engine;
    engine.rootContext()->setContextProperty("backend", &backend);
    engine.load("qrc:///ui/main.qml");

    return application.exec();
}

#include "main.moc"

Main.qml

import QtQuick 2.10
import QtQuick.Controls 2.3
import QtQuick.Layouts 1.1

ApplicationWindow {
    id: window

    width: 200
    height: 250
    visible: true

    ColumnLayout {
        anchors.fill: parent
        anchors.margins: 10

        ListView {

            Layout.fillWidth: true
            Layout.fillHeight: true

            model: backend.createModel()
            delegate: Text {
                anchors.horizontalCenter: parent.horizontalCenter
                text: model.display
            }
        }

        Button {
            Layout.alignment: Qt.AlignCenter
            text: qsTr("Garbage Collect")
            onClicked: gc()
        }
    }
}

Это скриншот программы:

В тот момент, когда пользователь нажимает на кнопку, сборщик мусора запускается и уничтожает модель ptr (уничтожение становится очевидным из "«Создание» и «Уничтожение» (вывод на стандартный вывод).

Мне интересно узнать, почему указатель был уничтожен?Я заметил, что он не установил ListView в качестве своего родителя, что достаточно справедливо, я подумал, что механизм QML использовал бы некоторую форму ссылочного указателя, чтобы попытаться отследить, кто все еще держитссылка на это.Есть ли документ, который дает более полное представление о том, как реализована сборка / владение мусором.

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

1 Ответ

0 голосов
/ 12 сентября 2018

Кажется, что причина уничтожения заключается в том, что на объект не ссылаются в QML, например, если он назначен свойству, сборщик мусора не повлияет на него:

ApplicationWindow {
    id: window
    width: 200
    height: 250
    visible: true
    property var mymodel: backend.createModel()
    ColumnLayout {
        anchors.fill: parent
        anchors.margins: 10
        ListView {
            Layout.fillWidth: true
            Layout.fillHeight: true
            model: mymodel
            delegate: Text {
                anchors.horizontalCenter: parent.horizontalCenter
                text: display
            }
        }
        Button {
            Layout.alignment: Qt.AlignCenter
            text: qsTr("Garbage Collect")
            onClicked: gc()
        }
    }
}
...