Qt5.6 QML,为什么垃圾回收后动态模型会被销毁?

标签 qt qml qt5 qt5.6

我的组件数量不定,因此我尝试为每个组件提供自己的模型。在这个例子中,我只是创建了一个,但想法是一样的。

GC() 有点随机,因此在示例中,我在单击后强制执行 gc() 以解决问题。发生的情况是 model 被破坏并变为 null。之后click方法就无法使用了。

main.qml:

import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtQuick.Layouts 1.2

import com.example.qml 1.0

ApplicationWindow
{
    visible: true
    width: 640
    height: 480

    // builder of dynamic models
    ModelFactory { id: maker }

    Column
    {
        anchors.fill: parent
        Repeater
        {
            // create dynamic model
            model: maker.makeModel();
            delegate: Label
            {
                id: label
                text: model.name

                MouseArea
                {
                    anchors.fill: parent
                    onClicked:
                    {
                        // works once until gc()
                        console.log("clicked on " + model.name)

                        // wont work anymore. model is destroyed
                        gc();
                    }
                }
            }

        }
    }
}

c++/mymodel.h:

#include <QAbstractListModel>
#include <QQmlApplicationEngine>
#include <QObject>
#include <QString>
#include <QDebug>

class BoxModel : public QAbstractListModel
{
    Q_OBJECT

public:

    ~BoxModel()
    {
        // see that it does get destroyed
        qDebug() << "~BoxModel()";
    }

    int rowCount(const QModelIndex& parent = QModelIndex()) const override
    {
        return 5;
    }  

    QVariant data(const QModelIndex &index, int role) const override
    {
        int ix = index.row();
        if (ix < 1) return "Larry";
        if (ix < 2) return "Barry";
        if (ix < 3) return "Gary";
        if (ix < 4) return "Harry";
        return "Sally";
    }

    QHash<int, QByteArray> roleNames() const override
    {
        QHash<int, QByteArray> roles;
        roles[Qt::UserRole+1] = "name";
        return roles;
    }

};

class ModelFactory: public QObject
{
    Q_OBJECT

public:

    Q_INVOKABLE BoxModel* makeModel()
    {
        return new BoxModel();
    }    
};

main.cpp 只是注册类型:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <qqmlcontext.h>
#include <qqml.h>
#include <QtQuick/qquickitem.h>
#include <QtQuick/qquickview.h>
#include "mymodel.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;

    qmlRegisterType<BoxModel>("com.example.qml", 1, 0, "BoxModel");
    qmlRegisterType<ModelFactory>("com.example.qml", 1, 0, "ModelFactory");

    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    return app.exec();
}

你所看到的:

runtime

单击任意名称。它将工作一次,之后它们将被取消定义,因为 model 变为 null。

例如

qml: clicked on Sally
~BoxModel()
qml: clicked on undefined

我的问题是为什么是这样,当我仍然有引用它时?

在示例中,onClicked 可以更改为 label.text 而不是 model.name 来修复,但是真实的 问题是,一般来说,对象可以随时访问模型以获取任何数据。例如,当盒子需要重画时。数据随机消失,具体取决于 GC。

我尝试过让 c++ 管理动态模型的生命周期。如果我知道 QML 何时完成,这可能会起作用。

感谢您提供信息和想法。

在Windows 8.1/qt5.6mingw上运行

EDIT1:文件作为要点, https://gist.github.com/anonymous/86118b67ec804e6149423c14792f312d

最佳答案

正如库巴所说,这确实看起来像是一个错误。但是,您可以采取另一种方法,通过 QQmlEngine::setObjectOwnership() 自行获取模型的所有权。 。具体来说,改变

Q_INVOKABLE BoxModel* makeModel()
{
    return new BoxModel();
}

Q_INVOKABLE BoxModel* makeModel()
{
    BoxModel *model = new BoxModel(this);
    QQmlEngine::setObjectOwnership(model, QQmlEngine::CppOwnership);
    return model;
}

将修复此问题(请记住将返回的模型作为 BoxModel 的父级,以便正确删除它)。解释了该行为的原因 here :

Generally an application doesn't need to set an object's ownership explicitly. QML uses a heuristic to set the default ownership. By default, an object that is created by QML has JavaScriptOwnership. The exception to this are the root objects created by calling QQmlComponent::create() or QQmlComponent::beginCreate(), which have CppOwnership by default. The ownership of these root-level objects is considered to have been transferred to the C++ caller.

Objects not-created by QML have CppOwnership by default. The exception to this are objects returned from C++ method calls; their ownership will be set to JavaScriptOwnership. This applies only to explicit invocations of Q_INVOKABLE methods or slots, but not to property getter invocations.

关于Qt5.6 QML,为什么垃圾回收后动态模型会被销毁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37325792/

相关文章:

python - 如何检测 PySide Gui 上的任何鼠标点击?

c++ - 使用 Qt Signal and Slot 实现 c++ Callback

c++ - 使用 Visual Studio/Qt 中止执行

Qt-Qml调试已启用。仅在安全环境下使用

qt - 如何在 QML 中调用电话或发送电子邮件?

cmake - Qt5 cmake找不到ui的头文件

c++ - Qt tableView - 添加颜色

c++ - 此应用程序启动失败,因为它找不到或加载 Qt 平台插件 "windows"

qt - 如何在 QtWebEngine QML 应用程序中设置用户代理

c++ - Qt:一旦显示,如何将光标焦点转移到“查找”对话框/工具中的字段?