将对象从 c++ 发送到 qml。空闲内存呢?

Posted

技术标签:

【中文标题】将对象从 c++ 发送到 qml。空闲内存呢?【英文标题】:Send object from c++ to qml. What about free memory? 【发布时间】:2016-04-08 03:57:24 【问题描述】:

有一个继承自 QAbstractListModel 的模型,我在 qml 中使用它。该模型的属性之一是参数,它们特定于该模型的元素类型。这是该类 TemperatureParam 的参数的一个元素,另一个是 DifrentParamType,第三个仍然是……如何将对象传递给 qml 并确保在使用后释放内存?下面的代码现在可以按我的需要运行,但在我看来它并不安全。

Param 类如此琐碎:

class QuickTemperatureParam : public QObject

    Q_OBJECT
    Q_PROPERTY(float param1 READ param1 WRITE setParam1)
//...
;

模型类(这就是我要问的):

class SectionsModel : public QAbstractListModel

//...
QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override

//...
    int type = getType( idx );
    if (type == 1)
    
        auto p = new QuickTemperatureParam( idx );
        p->deleteLater(); // This is all right or no?
        return qVariantFromValue(p);
    
    else if (type == 2)
    //...

;

QML 是这样的:

ListView 
    model: sectionsModel

    delegate: Rectangle 
        color: model.statusColor

        ItemDelegate 
            text: model.title
            highlighted: ListView.isCurrentItem

            onPressed:
                switch ( model.type )
                
                case SectionType.Temperature:
                    temperatureParam.openItem(model)
                    break;
                case SectionType.Lighting:
                    lightingParam.open(model)
                    break;
                
        
    


Popup 
    id: temperatureParam

    function openItem(model)
    
        var p = model.param

        params.itemAt(0).range.from = params.itemAt(1).range.from = p.min
        params.itemAt(0).range.to = params.itemAt(1).range.to = p.max

        params.itemAt(0).range.setValues( p.dayMin, p.dayMax )
        params.itemAt(1).range.setValues( p.nightMin, p.nightMax )

        open()
    

【问题讨论】:

【参考方案1】:

根据documentation:

当数据从 C++ 传输到 QML 时,数据的所有权 始终使用 C++。此规则的例外是当 QObject 从显式 C++ 方法调用返回:在这种情况下,QML 引擎假定对象的所有权,除非该对象的所有权 对象已通过调用显式设置为保留在 C++ 中 QQmlEngine::setObjectOwnership() 与 QQmlEngine::CppOwnership 指定。

通常,应用程序不需要明确设置对象的所有权。如您所见here,默认情况下,由 QML 创建的对象具有javascriptOwnership

从 C++ 方法调用返回的对象也将设置为 JavaScriptOwnership,但这仅适用于显式调用 Q_INVOKABLE 方法或槽。

因为方法data不是显式的C++方法调用,你应该考虑将对象所有权设置为QQmlEngine::JavaScriptOwnership调用setObjectOwnership()

所以,一般来说:

如果您希望 QML 销毁对象,请不要使用 QQmlEngine::CppOwnership。相关的数据将在适当的时候被删除(即在垃圾收集器发现没有更多对该值的实时引用之后) QSharedPointer 可能不起作用。你有更多信息here。

【讨论】:

哇,我不知道。谢谢回复。但是我尝试了 setObjectOwnership,它对我的​​效果比 deleteLater 差得多。如果我离开 deleteLater 是否足够安全,如果 QQmlEngine 和我的模型是在同一个线程中创建的。退出函数 temperatureParam.openItem (QML) 后,我不再需要这个对象。或者该对象可能之前被删除? @lirik90 谢谢你!好吧,我没有说要删除deleteLater 代码行。对不起,如果我没有正确解释自己:(如果datatemperatureParam.openItem 期间执行(我是对的吗?),那么我认为p 不会被删除,除非您将其所有权设置为QQmlEngine::JavaScriptOwnership 所以,为了安全起见,将new 对象传递给QML 时始终设置QQmlEngine::JavaScriptOwnership 是否合理,即使上述暗示QML 将获得所有权?在这种情况下,我会考虑这样做以使传输更清晰:template <typename T> T* TransferObjectOwnershipToJavaScript(std::unique_ptr<T> ptr) T* result = ptr.get(); QQmlEngine::setObjectOwnership(ptr.release(), QQmlEngine::JavaScriptOwnership); return result;

以上是关于将对象从 c++ 发送到 qml。空闲内存呢?的主要内容,如果未能解决你的问题,请参考以下文章

如何将信号从一个 qml 发送到另一个

QML 绑定整数属性 - c++ 中的更改未发送到 QML

从 C++ (Qt5) 向 QML 项目发送信号

将二进制数据从 QML 传递到 C++

从物品中获取窗口

如何将元组列表从 python 发送和解包到 qml?