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

Create custom C++ Object in QML and store it in a C++ Model

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

customObject 是一个非可视对象。

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

但是现在我想在 QML 中动态地从我的自定义 Class 创建对象并将它们也存储在模型中。这就是我挣扎的地方。我希望我可以像这样创建一个 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);
}

我不知道这是否是最短路线,但这应该适合您。我从其他支持者的基础知识开始。

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_
}

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

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

所以它应该是这样的:

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

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

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