在 QML 中创建自定义 C++ 对象并将其存储在 C++ 模型中

Posted

技术标签:

【中文标题】在 QML 中创建自定义 C++ 对象并将其存储在 C++ 模型中【英文标题】:Create custom C++ Object in QML and store it in a C++ Model 【发布时间】:2015-08-07 12:36:48 【问题描述】:

我已经用 C++ 编写了一个客户类(从 QObject 继承),并使用 QML 成功注册了它的类型。目前,我正在 C++ 中静态创建此类的对象,并将指向它们的指针存储在实现 QAbstractListModel 的模型中。在 QML 中,我可以完美地访问对象作为模型的项目。

customObject 是非可视对象。

我在 GUI 应用程序 (QML) 的另一部分中使用委托可视化 ListView 中的对象。

但是现在我想在 QML 中动态地从我的自定义类创建对象,并将它们也存储在模型中。这就是我挣扎的地方。我希望我可以像这样创建一个 customObject:

import com.myProject.myCustomStuff 1.0

...


Button
   id: createObjBtn
   text: "create new CustomObj"
   onClicked:
      var obj = MyCustomObj;
      myObjectManager.addObj(obj);  // object holding the implemented QAbstactListModel
      console.log(typeof(obj)); // returns [Object object]
      console.log(Qt.isQtObject(obj)) // returns false
   

我会很感激你的想法。也许有人知道正确执行此操作的方法?

谢谢!

更新 1

根据 Simon-Warta 的要求,这里是 MyCustomObj 的构造函数实现。

MyCustomObj.cpp

MyCustomObj::MyCustomObj(QObject *parent) : QObject(parent)

    QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership);

【问题讨论】:

【参考方案1】:

您混淆了类的功能意图。 QAbstractListModel 旨在作为容器的包装器,是的,您可以将容器放在 QAbstractListModel 派生类中,但您实际上不必这样做,容器几乎可以是任何 C++ 类,甚至不一定QObject 派生,它可以只是一个QVector<Something>,您可以通过指针从模型中访问它。这适用于您有很多对象且并非所有对象都需要始终拥有模型的情况,因为这些模型非常繁重。

您实际上不需要关心所有权,将其留在 C++ 端,实际的对象创建也是如此,有一个称为插槽,将新对象添加到容器中,同时还使用模型的 @ 987654325@ 和 endInsertRows() 以便通知任何视图以有效更新,新对象也应该在该插槽中创建,您可以从 QML 传递所需的任何数据,只需确保所有数据都注册到 Qt 元系统,因此它可以与 QVariant 一起用于 QML-C++ 互操作。

所以应该是这样的:

myObjectManager.create(/* any needed data goes here */)

create() 将最终数据传递到 C++ 端,在此创建对象,调用 beginInsertRows(),将对象添加到模型的底层存储,然后调用 endInsertRows(),就完成了。

我更愿意将所有权保留在 C++ 端(我不是明确表示),我可以控制它。在处理 C++ 和 QML 之间共享的对象所有权时,Qt 有点糟糕。理想情况下,应该有一个可以在 C++ 和 QML 上工作的共享指针类,因此一旦对它的所有引用都消失了,该对象就会被删除。但这不是“Qt 方式”——Qt 共享指针不适用于 QML,标准 C++ 共享指针也不适用,实际上有一个完全不同的 QML 共享引用类,它甚至不是公共 API 的一部分IIRC,非常丑陋和短视的设计,只会扩大 C++ 和 QML 之间的差距以及相关的不便因素。

【讨论】:

谢谢!这听起来是非常好的建议。我将在 C++ 中为我的 myObjectManager 类创建一个工厂方法,然后在 C++ 中完全处理对象的创建、存储和删除。 我对“QAbstractListModel 旨在作为容器的包装器感到困惑,是的,您可以将容器放在 QAbstractListModel 派生类中,但您实际上不必”...可以你再解释一下?我认为我们总是将一个容器放在里面(在它的派生类中),这也是一种包装它,但你似乎说这是两个不同的东西? @zar - 例如,就我而言,我有数百万个对象,但我不需要一次将所有对象都可视化。所以在这种情况下,我使用了一个不包含数据的“附件”模型,只是为列表视图提供了一个列表模型接口来访问它。模型类的目的是提供对数据的访问,与实际数据位置无关。 听起来很有趣,但我不清楚你是如何实现“附加”模型的,而不是仅仅从QAbstractListModel 派生并在那里拥有容器?你能用委托模型代替吗?事实上,这就是我计划用来显示模型数据的子部分的,但我的整体数据并没有那么大。【参考方案2】:

我不知道这是否是最短的方法,但这应该适合你。我从其他支持投票者的基础知识开始。

MyCustomObj.h

class MyCustomObj : public QObject

    Q_OBJECT

public:
    // ...

    Q_INVOKABLE void funfunction();

MyCustomObj.cpp

void MyCustomObj::funfunction()

    qDebug("Fun with QML");

main.cpp

qmlRegisterType<MyCustomObj>("com.myProject.myCustomStuff", 1, 0, "MyCustomObj");

app.qml

import com.myProject.myCustomStuff 1.0

ApplicationWindow 
    id: mainWindow

    Component 
        id: myComponent

        MyCustomObj 

        
    

    Component.onCompleted: 
        var obj = myComponent.createObject(mainWindow)
        if (!obj) console.error("Error creating object")

        console.log(typeof(obj))
        console.log(Qt.isQtObject(obj))

        obj.funfunction()
    


createObject 可以选择将属性传递给组件。

存储

由于您现在负责删除对象,因此我建议使用共享指针,以便在销毁 List 时销毁对象。

您的QAbstactListModel 实现,我们称之为MyModel 有一个类似的加法器函数:

#include <memory> // for std::shared_ptr

class MyModel : public QAbstractListModel

    Q_OBJECT

public:

    // ..

    Q_INVOKABLE addObj(MyCustomObj* obj)
    
        objectlist_.append(std::shared_ptr<MyCustomObj>(obj));
    

private:
    QList<std::shared_ptr<MyCustomObj>> objectlist_

【讨论】:

感谢您的回答。但我认为这不是我想要的。我想将动态生成的 myCustomObj 存储在 C++ 模型(实现 QAbstractListModel)中。此模型包含对所有 . 的引用 好吧,这将是更进一步的步骤。您是否考虑过所有权和资源管理?您希望 Javscript 或 Cpp 拥有生成的对象吗? 是的,在 MyCustomObj 的构造函数中,我专门将所有权分配给 C++。 这行不通,因为 Javaascript 和 C++ 都会在某个时候尝试销毁该对象。你能添加这个构造函数的代码吗?据我所知,您不应该在 QML 中创建这些对象,而应该在 C++ 中创建这些对象 您的构造函数对我来说看起来不错。我添加了一段关于addObj

以上是关于在 QML 中创建自定义 C++ 对象并将其存储在 C++ 模型中的主要内容,如果未能解决你的问题,请参考以下文章

如何在文件夹中创建自定义页面模板

qt quick QML 应用程序的自定义样式页面(如 HTML 和 CSS)

在PyQt中创建MapQuickItem并将其添加到Map中

如何在 python 中创建路径并将其显示在 qml 画布上

如何在 QML 中访问 C++ 类对象,而不是在 QML 中创建单独的对象?

如何在 GraphQL 中创建自定义对象列表