【问题标题】:Create qml object dynamically from c++ object (by using setContextProperty)从 c++ 对象动态创建 qml 对象(使用 setContextProperty)
【发布时间】:2019-03-25 18:36:31
【问题描述】:

我正在尝试使用 c++ 类的对象在 c++ 中动态创建一个 qml 对象。下面是我的方法的最小代码。执行此代码并单击后,应用程序崩溃(请参阅 main.qml 中的注释)。

我已经粘贴了下面的代码,可以下载here

ma​​in.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "scene.h"
int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;

    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    scene sc(engine);

    QQmlContext* context = engine.rootContext();
    context->setContextProperty("sc", &sc);

    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

scene.h

#ifndef SCENE_H
#define SCENE_H

#include <QObject>
#include <QQmlApplicationEngine>
#include <QQmlComponent>
class scene : public QObject
{
    Q_OBJECT
public:
    explicit scene(QQmlApplicationEngine& engine, QObject *parent = nullptr);
    QQmlApplicationEngine& engine;

public slots:
    void create_rect_object();
};

#endif // SCENE_H

场景.cpp

#include "scene.h"

scene::scene(QQmlApplicationEngine &engine, QObject *parent) : engine(this->engine),QObject(parent)
{

}    
void scene::create_rect_object()
{
    QQmlComponent component(&engine, QUrl::fromLocalFile("myrect.qml"));
    QObject *object = component.create();
    object->setProperty("width", 200);
    object->setProperty("height", 150);
    object->setProperty("color", "blue");
}

main.qml

import QtQuick 2.11
import QtQuick.Window 2.11

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")
    Rectangle{
        anchors.fill: parent
        color: "red"
        MouseArea{
            anchors.fill: parent
            onClicked: {
                console.log("Before click");
                sc.create_rect_object(); // application is crashing here
                console.log("after click");
            }
        }
    }
}

myrect.qml

import QtQuick 2.0

Rectangle {
    id:id_rec
    width: 100
    height: 100
    color: "green"
    x:0
    y:0
}

更新

要创建的对象不是主窗口根的子项,而是主窗口根的子项链中的一项的子项。伪结构如下所示。

ma​​in.qml

Window {       

    customitem1{
        id:id_ci1

    }    
    customitem2{
        id:id_ci1        
    }       
}

customitem1.qml

Item {       

    customitem3{
        id:id_ci3

    }    
    customitem3{
        id:id_ci4        
    }       
}

【问题讨论】:

  • 你创建这些对象的逻辑是什么?
  • 逻辑到底是什么意思?
  • 你将如何创建这些对象?随机还是有你正在遵循的方案?
  • 这些对象由用户拖放,然后结束位置,属性保存在数据库中。稍后重新加载数据库时,这些对象应位于具有相同属性的相同位置。总之恢复以前的上下文。
  • 我说的是这些对象的 CREATION,而不是 INTERACTION 或 POST-CREATION

标签: c++ qml qtquick2 qqmlcomponent qqmlcontext


【解决方案1】:

[更新]

您有两个崩溃错误和一个不显示矩形的错误

1.你的scene构造函数成员初始化列表是虚假的,导致应用崩溃

(提示:为类成员使用不同的命名方式,为它们添加前缀m_ 例如:m_engine 表示可读性,不要让混淆)

//Correct WAY
class Something
{
 private:
    int m_value1;
    double m_value2;
    char m_value3;

 public:
    //#################  YOUR CASE  ###############################
    Something(int number) : m_value1(number), m_value2(2.2), m_value3('c') // directly initialize our member variables
    {
    // No need for assignment here
    }
    //#############################################################
    Something() : m_value1(1), m_value2(2.2), m_value3('c') // directly initialize our member variables
    {
    // No need for assignment here
    }
    void print()
    {
         std::cout << "Something(" << m_value1 << ", " << m_value2 << ", " << m_value3 << ")\n";
    }
}

应该是这样的:

scene::scene(QQmlApplicationEngine &engine, QObject *parent) : engine(engine),QObject(parent)

而不是

scene::scene(QQmlApplicationEngine &engine, QObject *parent) : engine(this->engine),QObject(parent)

2.myrect.qml 中的url 是您在运行时 找不到的本地文件导致应用程序崩溃的一种补救措施是从您的qrc 文件中加载它

 QQmlComponent component(&engine, QUrl("qrc:/myrect.qml"));

3.点击后你会注意到没有矩形,这是因为创建的矩形没有父级,并且通过更改您的create_rect_object()(在此示例中,父级是我们窗口的不可见根@987654332 @) 你会得到一些矩形:)

//A QQuickWindow always has a single invisible root item containing all of its content.
//To add items to this window, reparent the items to the contentItem or to an existing item in the scene.
//http://doc.qt.io/qt-5/qquickwindow.html#contentItem-prop



void scene::create_rect_object()
{
    QQmlComponent component(&engine, QUrl("qrc:/myrect.qml"));

    QObject *object = component.create();
    QQuickItem *item = qobject_cast<QQuickItem*>(object);
    // Set the parent of our created qml rect
    item->setParentItem((QQuickItem*)((QQuickWindow *) engine.rootObjects()[0])->contentItem());
    //Set some random position and color
    item->setProperty("color", QColor::fromRgb(QRandomGenerator::global()->generate()));
    item->setX(20+qFloor(QRandomGenerator::global()->generateDouble()*20));
    item->setY(20+qFloor(QRandomGenerator::global()->generateDouble()*20));

}

从 C++ 中查找 QML 对象

要查找对象并将其用作parentItem,您必须设置qml 对象的objectName

Rectangle {
             ...
             objectName : "rect_1"
             ...
}

在 C++ 中

QObject* obj = dynamic_cast<QObject*>(engine.rootObjects()[0]).findChild("rect_1");

【讨论】:

  • 感谢您的回答,它适用于上述代码,但我对 setParentItem 有疑问,因为我的对象不在主窗口中。我的意思是要创建的对象在子链中。我会用更多细节更新问题。
  • @nayab 检查更新,我们现在完成了 :) 如果它适合您的需要,请不要忘记标记答案
  • 我已经尝试找到父对象但没有找到。无论如何感谢您的帮助。我已经用javascript解决了。
  • @nayab 尝试了解您的对象树和子对象
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-12-10
  • 2017-05-04
  • 2014-06-03
  • 1970-01-01
  • 1970-01-01
  • 2014-12-22
  • 2021-08-10
相关资源
最近更新 更多