Qt:在运行时从C++代码创建QML组件时,onChildrenChanged未启动

0 c++ qt object qml

对于项目,我需要在运行时从C++创建QML组件.

我的一般架构如下:

PROJECT1:

  • Engine.h
  • Engine.cpp
  • CustObject.h
  • CustObject.cpp
  • Plugin.h
  • Plugin.cpp
  • Dummy.qml

项目2:

  • main.cpp中
  • main.qml

我想要做的是将Engine.cpp实例化为QML对象(可能因为我在Plugin类中注册它并使其可用于Project2)然后从Engine创建动态CustObject实例(它们也被Project2注册使用) .最后我希望如果我写:

ApplicationWindow{
id: window
visible: true
    Engine{
        id: eng1
        CustObject{
            id: custObj1
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这与编写类似的内容相同

ApplicationWindow {
    id: window
    visible: true

    Button {
        text: "add new child"
        onClicked: {
            console.log("QML: Number children before", eng1.children.length);
            eng1.addNewChildren();
            console.log("QML: Number children after", eng1.children.length);
        }
    }
    Engine{
        id: eng1
        onChildrenChanged: console.log("Changed")
    }
}
Run Code Online (Sandbox Code Playgroud)

我应该看到孩子的数量增加,并且应该启动从eng1开始的onChildrenChanged.

问题是既没有增加子项数,也没有启动onChildrenChanged信号.

我还有另外一个问题,为了在父类中添加一个子项,在我的情况下,我使用了QQMLComponent类的函数QQmlComponent(QQmlEngine*engine,const QUrl&url,QObject*parent = 0).但我找不到将CustObject类转换为QUrl的方法,因为它不是.qml文件.

因此,我首先尝试添加一个名为Dummy.qml的虚拟qml对象,而不是CustObject对象.Dummy.qml看起来像这样:

import QtQuick 2.0

Item {
    property int nb: 1
}
Run Code Online (Sandbox Code Playgroud)

我的Engine类的代码如下所示:

Engine.h:

#ifndef ENGINE_H
#define ENGINE_H

#include <QQuickItem>
#include <QQmlComponent>
#include <QQmlEngine>
#include <QQmlContext>


class Engine : public QQuickItem{
    Q_OBJECT
public:
    explicit Engine(QQuickItem* parent = 0);

    virtual ~Engine();

    Q_INVOKABLE QObject* addNewChildren();

};

#endif // ENGINE_H
Run Code Online (Sandbox Code Playgroud)

Engine.cpp:

#include "Engine.h"


Engine::Engine(QQuickItem* parent) :
    QQuickItem(parent)
{
}

Engine::~Engine(){ }


QObject* Engine::addNewChildren(){

    qDebug() << "CPP: Number children before " << this->children().size();

    QObject* parentEntity = this;
    QQmlComponent* childrenEntity;
    QQmlComponent component(qmlEngine(this), QUrl("qrc:///src/Dummy.qml"));
    QQuickItem *childrenItem = qobject_cast<QQuickItem*>(component.create());
    QQmlEngine::setObjectOwnership(childrenItem, QQmlEngine::CppOwnership);
    childrenItem->setParent(parentEntity);
    childrenItem->setProperty("nb", 2);

    qDebug() << "CPP: Number children after" << this->children().size();

    //qDebug() << "Property value:" << QQmlProperty::read(childrenItem, "nb").toInt();

    return childrenItem;
}
Run Code Online (Sandbox Code Playgroud)

但是当我运行main.qml时我的输出如下:

    qml: QML: Number children before 0
    CPP: Number children before  0
    CPP: Number children after 1
    qml: QML: Number children after 0
Run Code Online (Sandbox Code Playgroud)

由于以下错误,我评论了对应于QQmlProperty :: read的行:"嵌套名称说明符qDebug中使用的不完整类型'QQmlProperty'()<<"属性值:"<< QQmlProperty :: read(childrenItem,"nb" ).toInt();" ^

因此,我有以下问题:

  1. 为什么从qml中看不到儿童增加的数量(但是从cpp可见)?
  2. 为什么onChildrenChanged没有从qml启动?
  3. 如何添加动态CustObject类(从Project2的角度来看,它可以作为qml对象显示,因为它已注册)而不是Dummy.qml?
  4. 如何在C++创建之后读取动态添加对象的属性(即如何使用QQMlProperty :: read)?

非常感谢你提供给我的任何帮助!

Tho*_*ire 6

为什么从qml中看不到儿童增加的数量(但是从cpp可见)?

QML不使用QObject::children(),而是使用QQuickItem::childItems().是的,没错,有两个不同的孩子列表,一个来自QObject,一个来自QQuickItem.两者都有不同的用途:QObject中的一个主要用于内存管理(当父项被删除时,子项被删除),而QQuickItem中的一个用于"视觉层次",例如,孩子被绘制在父母之上.更多详细信息可在文档中找到.

为什么onChildrenChanged没有从qml启动?

因为onChildrenChanged只有在QQuickItem::childItems()发生变化时才发光,而它却没有.setParentItem()除了setParent()解决之外,还要打电话.

如何添加动态CustObject类(从Project2的角度来看,它可以作为qml对象显示,因为它已注册)而不是Dummy.qml?

只需自己创建对象并设置parentparentItem.这里没有必要使用QQmlComponent.

QObject childrenItem = new CustObject();
childrenItem->setParent(parentEntity);
childrenItem->setParentItem(parentEntity);
Run Code Online (Sandbox Code Playgroud)

如何在C++创建之后读取动态添加对象的属性(即如何使用QQMlProperty :: read)?

调用QQuickItem::childItems()应该做的伎俩,不需要读取属性.FWIW,#include <QQmlProperty>代码中可能缺少一些不起作用的代码.