【问题标题】:Qt: onChildrenChanged not launched when QML components are created at runtime from C++ codeQt:在运行时从 C++ 代码创建 QML 组件时未启动 onChildrenChanged
【发布时间】:2016-07-11 03:50:55
【问题描述】:

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

我的总体架构如下:

项目1:

  • Engine.h
  • Engine.cpp
  • CustObject.h
  • CustObject.cpp
  • 插件.h
  • 插件.cpp
  • Dummy.qml

项目2:

  • main.cpp
  • main.qml

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

ApplicationWindow{
id: window
visible: true
    Engine{
        id: eng1
        CustObject{
            id: custObj1
        }
    }
}

这和写类似的东西是一样的

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")
    }
}

我应该看到孩子的数量增加了,应该从 eng1 启动 onChildrenChanged。

问题是孩子的数量既没有增加,也没有启动 onChildrenChanged 信号。

我还有另一个问题,为了向父级添加子级,在我的例子中是 eng1,我使用了 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
}

我的 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

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

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

    qml: QML: Number children before 0
    CPP: Number children before  0
    CPP: Number children after 1
    qml: QML: Number children after 0

由于以下错误,我注释了对应于 QQmlProperty::read 的行:“嵌套名称说明符中使用的不完整类型 'QQmlProperty' qDebug()

因此我有以下问题:

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

非常感谢您能给我的任何帮助!

【问题讨论】:

  • 这是一个私人信号,你不应该使用它。
  • 感谢您的快速回复!那么当一个孩子被添加到我的引擎时,我应该使用什么信号来执行操作?你有什么想法,为什么我的 children 变量没有从 qt 的角度更新,而是从 c++ 更新是的?
  • Qt 的内部设计相当静态且不灵活,您实际上没有选择更改或利用它的选项。你可以覆盖它,但是谁知道你可能会破坏什么,总而言之,它并不漂亮。更好的策略是改变您的设计以解决 Qt 的限制。拥有自己的自定义函数来创建对象并发出自定义信号来通知。
  • 谢谢,但是你告诉我 onChildrenChanged 不应该直接在任何 qml 代码中使用?孩子变量呢?它不是一个可靠的变量,可用于随时了解父母的子女人数吗? (在我的情况下,它不可靠,因为它不会从 qml 的角度改变)无论如何我会研究一个新的设计。我的想法是为 Engine 类保留一个 List 子类,并有一个关联的信号链接到这个列表。你认为这是个好主意吗?你对我的其他 3 个问题有什么想法吗? (1,3 和 4)

标签: c++ qt object qml


【解决方案1】:

为什么从 qml 中看不到子节点的数量增量(但从 cpp 中可见)?

QML 不使用QObject::children(),而是使用QQuickItem::childItems()。是的,没错,有两个不同的孩子列表,一个来自QObject,一个来自QQuickItem。两者都有不同的用途:来自 QObject 的一个主要用于内存管理(删除父级时删除子级),而来自 QQuickItem 的一个用于“视觉层次结构”,例如孩子们被吸引到他们的父母身上。更多详细信息,请访问the docs

为什么 onChildrenChanged 没有从 qml 启动?

因为 onChildrenChanged 仅在 QQuickItem::childItems() 更改时才会发出,而事实并非如此。除了 setParent() 之外,请致电 setParentItem() 来解决此问题。

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

只需自己创建对象并设置parentparentItem。此处无需使用QQmlComponent

QObject childrenItem = new CustObject();
childrenItem->setParent(parentEntity);
childrenItem->setParentItem(parentEntity);

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

调用QQuickItem::childItems() 应该可以解决问题,无需读取属性。 FWIW,代码中可能缺少#include &lt;QQmlProperty&gt;,但不起作用。

【讨论】:

  • 非常感谢!现在它可以工作了:) 我现在有另一个问题:我想动态创建我的 CustObject,但我想使用 QQmlComponent 的 beginCreate(QQmlContext *publicContext)。实际上,我希望在启动 onChildrenChanged 之前设置我的所有属性。有什么方法可以使用该功能并同时使用自定义组件?因为目前我只看到使用 loadUrl 和 qml 对象来使用该函数。
  • 我暂时看不到,建议你提出一个新问题,让其他人看到,这样你可能会得到一些答案。
猜你喜欢
  • 2012-05-17
  • 2023-03-13
  • 1970-01-01
  • 2018-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-11
相关资源
最近更新 更多