2

根据 Qt文档,每当QObject指针类型通过Q_INVOKABLE方法从 C++ 代码传递到 QML 时,都有一组规则确定谁负责该指针的生命周期。如果QObject是无父对象,则 QML 引擎隐含地负责获取指针的所有权。

在我的场景中,我希望我的前端 UI 表示由后端 C++ 代码生成/提供的列表模型。我的假设是,只要 QML 代码引用它,指针就会保持活动状态。下面的代码显示了精简的测试用例:

主文件

#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"

主.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 的要求。

4

1 回答 1

-1

似乎销毁的原因是因为该对象没有在 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()
        }
    }
}
于 2018-09-12T04:39:31.173 回答